From f76c82403888bb498973ec974dbfd20e4edb02fe Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Fri, 30 Jun 2017 20:13:51 +0200 Subject: nxcomp: Switch to autoreconf. --- Makefile | 16 +- debian/libxcomp-dev.install | 1 + debian/rules | 2 +- nx-X11/lib/X11/Imakefile | 6 +- nx-X11/programs/Xserver/Imakefile | 20 +- nxcomp/.gitignore | 23 +- nxcomp/ActionCache.cpp | 47 - nxcomp/ActionCache.h | 49 - nxcomp/Agent.cpp | 80 - nxcomp/Agent.h | 263 - nxcomp/Alpha.cpp | 134 - nxcomp/Alpha.h | 35 - nxcomp/Auth.cpp | 667 -- nxcomp/Auth.h | 127 - nxcomp/Bitmap.cpp | 114 - nxcomp/Bitmap.h | 36 - nxcomp/BlockCache.cpp | 77 - nxcomp/BlockCache.h | 67 - nxcomp/BlockCacheSet.cpp | 143 - nxcomp/BlockCacheSet.h | 49 - nxcomp/ChangeGC.cpp | 180 - nxcomp/ChangeGC.h | 185 - nxcomp/ChangeProperty.cpp | 187 - nxcomp/ChangeProperty.h | 189 - nxcomp/Channel.cpp | 2035 ---- nxcomp/Channel.h | 664 -- nxcomp/ChannelCache.cpp | 64 - nxcomp/ChannelCache.h | 61 - nxcomp/ChannelEndPoint.cpp | 345 - nxcomp/ChannelEndPoint.h | 71 - nxcomp/ChannelStore.h | 54 - nxcomp/CharCache.cpp | 69 - nxcomp/CharCache.h | 91 - nxcomp/Children.cpp | 1055 -- nxcomp/ClearArea.cpp | 121 - nxcomp/ClearArea.h | 182 - nxcomp/ClientCache.cpp | 388 - nxcomp/ClientCache.h | 417 - nxcomp/ClientChannel.cpp | 7877 -------------- nxcomp/ClientChannel.h | 434 - nxcomp/ClientProxy.cpp | 549 - nxcomp/ClientProxy.h | 113 - nxcomp/ClientReadBuffer.cpp | 174 - nxcomp/ClientReadBuffer.h | 65 - nxcomp/ClientStore.cpp | 222 - nxcomp/ClientStore.h | 143 - nxcomp/Colormap.cpp | 102 - nxcomp/Colormap.h | 32 - nxcomp/ConfigureWindow.cpp | 138 - nxcomp/ConfigureWindow.h | 178 - nxcomp/Control.cpp | 818 -- nxcomp/Control.h | 764 -- nxcomp/CopyArea.cpp | 195 - nxcomp/CopyArea.h | 192 - nxcomp/CreateGC.cpp | 190 - nxcomp/CreateGC.h | 186 - nxcomp/CreatePixmap.cpp | 276 - nxcomp/CreatePixmap.h | 162 - nxcomp/DecodeBuffer.cpp | 635 -- nxcomp/DecodeBuffer.h | 138 - nxcomp/EncodeBuffer.cpp | 619 -- nxcomp/EncodeBuffer.h | 183 - nxcomp/FillPoly.cpp | 235 - nxcomp/FillPoly.h | 200 - nxcomp/Fork.cpp | 106 - nxcomp/Fork.h | 31 - nxcomp/FreeCache.h | 42 - nxcomp/GenericChannel.cpp | 491 - nxcomp/GenericChannel.h | 440 - nxcomp/GenericReadBuffer.cpp | 78 - nxcomp/GenericReadBuffer.h | 61 - nxcomp/GenericReply.cpp | 298 - nxcomp/GenericReply.h | 161 - nxcomp/GenericRequest.cpp | 330 - nxcomp/GenericRequest.h | 160 - nxcomp/GetImage.cpp | 173 - nxcomp/GetImage.h | 190 - nxcomp/GetImageReply.cpp | 190 - nxcomp/GetImageReply.h | 150 - nxcomp/GetProperty.cpp | 115 - nxcomp/GetProperty.h | 183 - nxcomp/GetPropertyReply.cpp | 300 - nxcomp/GetPropertyReply.h | 160 - nxcomp/ImageText16.cpp | 227 - nxcomp/ImageText16.h | 190 - nxcomp/ImageText8.cpp | 227 - nxcomp/ImageText8.h | 190 - nxcomp/IntCache.cpp | 226 - nxcomp/IntCache.h | 119 - nxcomp/InternAtom.cpp | 127 - nxcomp/InternAtom.h | 178 - nxcomp/Jpeg.cpp | 886 -- nxcomp/Jpeg.h | 36 - nxcomp/Keeper.cpp | 608 -- nxcomp/Keeper.h | 199 - nxcomp/List.cpp | 108 - nxcomp/List.h | 95 - nxcomp/ListFontsReply.cpp | 209 - nxcomp/ListFontsReply.h | 146 - nxcomp/Loop.cpp | 16689 ---------------------------- nxcomp/MD5.c | 399 - nxcomp/MD5.h | 91 - nxcomp/Makefile.am | 21 + nxcomp/Makefile.in | 333 - nxcomp/Message.cpp | 2339 ---- nxcomp/Message.h | 1089 -- nxcomp/Misc.cpp | 1930 ---- nxcomp/Misc.h | 279 - nxcomp/NX.h | 471 - nxcomp/NXalert.h | 276 - nxcomp/NXmitshm.h | 56 - nxcomp/NXpack.h | 141 - nxcomp/NXproto.h | 447 - nxcomp/NXrender.h | 78 - nxcomp/NXvars.h | 201 - nxcomp/OpcodeCache.h | 53 - nxcomp/OpcodeStore.cpp | 84 - nxcomp/OpcodeStore.h | 91 - nxcomp/Pack.c | 180 - nxcomp/Pgn.cpp | 805 -- nxcomp/Pgn.h | 42 - nxcomp/Pipe.cpp | 429 - nxcomp/Pipe.h | 35 - nxcomp/PolyArc.cpp | 158 - nxcomp/PolyArc.h | 185 - nxcomp/PolyFillArc.cpp | 158 - nxcomp/PolyFillArc.h | 185 - nxcomp/PolyFillRectangle.cpp | 156 - nxcomp/PolyFillRectangle.h | 185 - nxcomp/PolyLine.cpp | 164 - nxcomp/PolyLine.h | 186 - nxcomp/PolyPoint.cpp | 164 - nxcomp/PolyPoint.h | 186 - nxcomp/PolySegment.cpp | 158 - nxcomp/PolySegment.h | 185 - nxcomp/PolyText16.cpp | 308 - nxcomp/PolyText16.h | 188 - nxcomp/PolyText8.cpp | 306 - nxcomp/PolyText8.h | 188 - nxcomp/Proxy.cpp | 6525 ----------- nxcomp/Proxy.h | 1276 --- nxcomp/ProxyReadBuffer.cpp | 207 - nxcomp/ProxyReadBuffer.h | 57 - nxcomp/PutImage.cpp | 407 - nxcomp/PutImage.h | 172 - nxcomp/PutPackedImage.cpp | 600 -- nxcomp/PutPackedImage.h | 218 - nxcomp/QueryFontReply.cpp | 150 - nxcomp/QueryFontReply.h | 136 - nxcomp/ReadBuffer.cpp | 635 -- nxcomp/ReadBuffer.h | 128 - nxcomp/RenderAddGlyphs.cpp | 229 - nxcomp/RenderAddGlyphs.h | 88 - nxcomp/RenderChangePicture.cpp | 234 - nxcomp/RenderChangePicture.h | 88 - nxcomp/RenderComposite.cpp | 396 - nxcomp/RenderComposite.h | 88 - nxcomp/RenderCompositeGlyphs.cpp | 625 -- nxcomp/RenderCompositeGlyphs.h | 100 - nxcomp/RenderCreateGlyphSet.cpp | 181 - nxcomp/RenderCreateGlyphSet.h | 88 - nxcomp/RenderCreatePicture.cpp | 274 - nxcomp/RenderCreatePicture.h | 88 - nxcomp/RenderExtension.cpp | 423 - nxcomp/RenderExtension.h | 504 - nxcomp/RenderFillRectangles.cpp | 233 - nxcomp/RenderFillRectangles.h | 88 - nxcomp/RenderFreeGlyphSet.cpp | 162 - nxcomp/RenderFreeGlyphSet.h | 88 - nxcomp/RenderFreePicture.cpp | 162 - nxcomp/RenderFreePicture.h | 88 - nxcomp/RenderGenericRequest.cpp | 266 - nxcomp/RenderGenericRequest.h | 89 - nxcomp/RenderMinorExtensionHeaders.h | 42 - nxcomp/RenderMinorExtensionMethods.h | 81 - nxcomp/RenderMinorExtensionTags.h | 194 - nxcomp/RenderPictureClip.cpp | 299 - nxcomp/RenderPictureClip.h | 88 - nxcomp/RenderPictureFilter.cpp | 274 - nxcomp/RenderPictureFilter.h | 88 - nxcomp/RenderPictureTransform.cpp | 210 - nxcomp/RenderPictureTransform.h | 88 - nxcomp/RenderTrapezoids.cpp | 368 - nxcomp/RenderTrapezoids.h | 88 - nxcomp/RenderTriangles.cpp | 358 - nxcomp/RenderTriangles.h | 88 - nxcomp/Rgb.cpp | 102 - nxcomp/Rgb.h | 36 - nxcomp/Rle.cpp | 102 - nxcomp/Rle.h | 36 - nxcomp/SendEvent.cpp | 300 - nxcomp/SendEvent.h | 195 - nxcomp/SequenceQueue.cpp | 170 - nxcomp/SequenceQueue.h | 91 - nxcomp/ServerCache.cpp | 191 - nxcomp/ServerCache.h | 303 - nxcomp/ServerChannel.cpp | 7942 -------------- nxcomp/ServerChannel.h | 529 - nxcomp/ServerProxy.cpp | 617 -- nxcomp/ServerProxy.h | 154 - nxcomp/ServerReadBuffer.cpp | 243 - nxcomp/ServerReadBuffer.h | 73 - nxcomp/ServerStore.cpp | 179 - nxcomp/ServerStore.h | 83 - nxcomp/SetClipRectangles.cpp | 150 - nxcomp/SetClipRectangles.h | 187 - nxcomp/SetUnpackAlpha.cpp | 262 - nxcomp/SetUnpackAlpha.h | 162 - nxcomp/SetUnpackColormap.cpp | 262 - nxcomp/SetUnpackColormap.h | 162 - nxcomp/SetUnpackGeometry.cpp | 301 - nxcomp/SetUnpackGeometry.h | 167 - nxcomp/ShapeExtension.cpp | 301 - nxcomp/ShapeExtension.h | 164 - nxcomp/Socket.cpp | 753 -- nxcomp/Socket.h | 96 - nxcomp/Split.cpp | 1835 ---- nxcomp/Split.h | 543 - nxcomp/StaticCompressor.cpp | 428 - nxcomp/StaticCompressor.h | 80 - nxcomp/Statistics.cpp | 2003 ---- nxcomp/Statistics.h | 745 -- nxcomp/Timestamp.cpp | 73 - nxcomp/Timestamp.h | 307 - nxcomp/TranslateCoords.cpp | 111 - nxcomp/TranslateCoords.h | 185 - nxcomp/Transport.cpp | 3064 ------ nxcomp/Transport.h | 577 - nxcomp/Types.h | 271 - nxcomp/Unpack.cpp | 1510 --- nxcomp/Unpack.h | 149 - nxcomp/Vars.c | 54 - nxcomp/Version.c | 97 - nxcomp/WriteBuffer.cpp | 496 - nxcomp/WriteBuffer.h | 134 - nxcomp/XidCache.cpp | 47 - nxcomp/XidCache.h | 49 - nxcomp/Z.cpp | 142 - nxcomp/Z.h | 37 - nxcomp/configure.ac | 83 + nxcomp/configure.in | 413 - nxcomp/include/MD5.h | 91 + nxcomp/include/NX.h | 471 + nxcomp/include/NXalert.h | 276 + nxcomp/include/NXpack.h | 141 + nxcomp/include/NXproto.h | 447 + nxcomp/include/NXvars.h | 201 + nxcomp/install-sh | 238 - nxcomp/m4/nx-macros.m4 | 1 + nxcomp/mkinstalldirs | 34 - nxcomp/nxcomp.pc.in | 2 +- nxcomp/src/ActionCache.cpp | 51 + nxcomp/src/ActionCache.h | 49 + nxcomp/src/Agent.cpp | 84 + nxcomp/src/Agent.h | 263 + nxcomp/src/Alpha.cpp | 138 + nxcomp/src/Alpha.h | 35 + nxcomp/src/Auth.cpp | 671 ++ nxcomp/src/Auth.h | 127 + nxcomp/src/Bitmap.cpp | 118 + nxcomp/src/Bitmap.h | 36 + nxcomp/src/BlockCache.cpp | 81 + nxcomp/src/BlockCache.h | 67 + nxcomp/src/BlockCacheSet.cpp | 147 + nxcomp/src/BlockCacheSet.h | 49 + nxcomp/src/ChangeGC.cpp | 184 + nxcomp/src/ChangeGC.h | 185 + nxcomp/src/ChangeProperty.cpp | 191 + nxcomp/src/ChangeProperty.h | 189 + nxcomp/src/Channel.cpp | 2039 ++++ nxcomp/src/Channel.h | 664 ++ nxcomp/src/ChannelCache.cpp | 68 + nxcomp/src/ChannelCache.h | 61 + nxcomp/src/ChannelEndPoint.cpp | 349 + nxcomp/src/ChannelEndPoint.h | 71 + nxcomp/src/ChannelStore.h | 54 + nxcomp/src/CharCache.cpp | 73 + nxcomp/src/CharCache.h | 91 + nxcomp/src/Children.cpp | 1059 ++ nxcomp/src/ClearArea.cpp | 125 + nxcomp/src/ClearArea.h | 182 + nxcomp/src/ClientCache.cpp | 392 + nxcomp/src/ClientCache.h | 417 + nxcomp/src/ClientChannel.cpp | 7881 ++++++++++++++ nxcomp/src/ClientChannel.h | 434 + nxcomp/src/ClientProxy.cpp | 553 + nxcomp/src/ClientProxy.h | 113 + nxcomp/src/ClientReadBuffer.cpp | 178 + nxcomp/src/ClientReadBuffer.h | 65 + nxcomp/src/ClientStore.cpp | 226 + nxcomp/src/ClientStore.h | 143 + nxcomp/src/Colormap.cpp | 106 + nxcomp/src/Colormap.h | 32 + nxcomp/src/ConfigureWindow.cpp | 142 + nxcomp/src/ConfigureWindow.h | 178 + nxcomp/src/Control.cpp | 822 ++ nxcomp/src/Control.h | 764 ++ nxcomp/src/CopyArea.cpp | 199 + nxcomp/src/CopyArea.h | 192 + nxcomp/src/CreateGC.cpp | 194 + nxcomp/src/CreateGC.h | 186 + nxcomp/src/CreatePixmap.cpp | 280 + nxcomp/src/CreatePixmap.h | 162 + nxcomp/src/DecodeBuffer.cpp | 639 ++ nxcomp/src/DecodeBuffer.h | 138 + nxcomp/src/EncodeBuffer.cpp | 623 ++ nxcomp/src/EncodeBuffer.h | 183 + nxcomp/src/FillPoly.cpp | 239 + nxcomp/src/FillPoly.h | 200 + nxcomp/src/Fork.cpp | 110 + nxcomp/src/Fork.h | 31 + nxcomp/src/FreeCache.h | 42 + nxcomp/src/GenericChannel.cpp | 495 + nxcomp/src/GenericChannel.h | 440 + nxcomp/src/GenericReadBuffer.cpp | 82 + nxcomp/src/GenericReadBuffer.h | 61 + nxcomp/src/GenericReply.cpp | 302 + nxcomp/src/GenericReply.h | 161 + nxcomp/src/GenericRequest.cpp | 334 + nxcomp/src/GenericRequest.h | 160 + nxcomp/src/GetImage.cpp | 177 + nxcomp/src/GetImage.h | 190 + nxcomp/src/GetImageReply.cpp | 194 + nxcomp/src/GetImageReply.h | 150 + nxcomp/src/GetProperty.cpp | 119 + nxcomp/src/GetProperty.h | 183 + nxcomp/src/GetPropertyReply.cpp | 304 + nxcomp/src/GetPropertyReply.h | 160 + nxcomp/src/ImageText16.cpp | 231 + nxcomp/src/ImageText16.h | 190 + nxcomp/src/ImageText8.cpp | 231 + nxcomp/src/ImageText8.h | 190 + nxcomp/src/IntCache.cpp | 230 + nxcomp/src/IntCache.h | 119 + nxcomp/src/InternAtom.cpp | 131 + nxcomp/src/InternAtom.h | 178 + nxcomp/src/Jpeg.cpp | 890 ++ nxcomp/src/Jpeg.h | 36 + nxcomp/src/Keeper.cpp | 612 ++ nxcomp/src/Keeper.h | 199 + nxcomp/src/List.cpp | 112 + nxcomp/src/List.h | 95 + nxcomp/src/ListFontsReply.cpp | 213 + nxcomp/src/ListFontsReply.h | 146 + nxcomp/src/Loop.cpp | 16693 +++++++++++++++++++++++++++++ nxcomp/src/MD5.c | 403 + nxcomp/src/Makefile.am | 146 + nxcomp/src/Message.cpp | 2343 ++++ nxcomp/src/Message.h | 1089 ++ nxcomp/src/Misc.cpp | 1934 ++++ nxcomp/src/Misc.h | 279 + nxcomp/src/NXmitshm.h | 56 + nxcomp/src/NXrender.h | 78 + nxcomp/src/OpcodeCache.h | 53 + nxcomp/src/OpcodeStore.cpp | 88 + nxcomp/src/OpcodeStore.h | 91 + nxcomp/src/Pack.c | 180 + nxcomp/src/Pgn.cpp | 809 ++ nxcomp/src/Pgn.h | 42 + nxcomp/src/Pipe.cpp | 433 + nxcomp/src/Pipe.h | 35 + nxcomp/src/PolyArc.cpp | 162 + nxcomp/src/PolyArc.h | 185 + nxcomp/src/PolyFillArc.cpp | 162 + nxcomp/src/PolyFillArc.h | 185 + nxcomp/src/PolyFillRectangle.cpp | 160 + nxcomp/src/PolyFillRectangle.h | 185 + nxcomp/src/PolyLine.cpp | 168 + nxcomp/src/PolyLine.h | 186 + nxcomp/src/PolyPoint.cpp | 168 + nxcomp/src/PolyPoint.h | 186 + nxcomp/src/PolySegment.cpp | 162 + nxcomp/src/PolySegment.h | 185 + nxcomp/src/PolyText16.cpp | 312 + nxcomp/src/PolyText16.h | 188 + nxcomp/src/PolyText8.cpp | 310 + nxcomp/src/PolyText8.h | 188 + nxcomp/src/Proxy.cpp | 6529 +++++++++++ nxcomp/src/Proxy.h | 1276 +++ nxcomp/src/ProxyReadBuffer.cpp | 211 + nxcomp/src/ProxyReadBuffer.h | 57 + nxcomp/src/PutImage.cpp | 411 + nxcomp/src/PutImage.h | 172 + nxcomp/src/PutPackedImage.cpp | 604 ++ nxcomp/src/PutPackedImage.h | 218 + nxcomp/src/QueryFontReply.cpp | 154 + nxcomp/src/QueryFontReply.h | 136 + nxcomp/src/ReadBuffer.cpp | 639 ++ nxcomp/src/ReadBuffer.h | 128 + nxcomp/src/RenderAddGlyphs.cpp | 233 + nxcomp/src/RenderAddGlyphs.h | 88 + nxcomp/src/RenderChangePicture.cpp | 238 + nxcomp/src/RenderChangePicture.h | 88 + nxcomp/src/RenderComposite.cpp | 400 + nxcomp/src/RenderComposite.h | 88 + nxcomp/src/RenderCompositeGlyphs.cpp | 629 ++ nxcomp/src/RenderCompositeGlyphs.h | 100 + nxcomp/src/RenderCreateGlyphSet.cpp | 185 + nxcomp/src/RenderCreateGlyphSet.h | 88 + nxcomp/src/RenderCreatePicture.cpp | 278 + nxcomp/src/RenderCreatePicture.h | 88 + nxcomp/src/RenderExtension.cpp | 427 + nxcomp/src/RenderExtension.h | 504 + nxcomp/src/RenderFillRectangles.cpp | 237 + nxcomp/src/RenderFillRectangles.h | 88 + nxcomp/src/RenderFreeGlyphSet.cpp | 166 + nxcomp/src/RenderFreeGlyphSet.h | 88 + nxcomp/src/RenderFreePicture.cpp | 166 + nxcomp/src/RenderFreePicture.h | 88 + nxcomp/src/RenderGenericRequest.cpp | 270 + nxcomp/src/RenderGenericRequest.h | 89 + nxcomp/src/RenderMinorExtensionHeaders.h | 42 + nxcomp/src/RenderMinorExtensionMethods.h | 81 + nxcomp/src/RenderMinorExtensionTags.h | 194 + nxcomp/src/RenderPictureClip.cpp | 303 + nxcomp/src/RenderPictureClip.h | 88 + nxcomp/src/RenderPictureFilter.cpp | 278 + nxcomp/src/RenderPictureFilter.h | 88 + nxcomp/src/RenderPictureTransform.cpp | 214 + nxcomp/src/RenderPictureTransform.h | 88 + nxcomp/src/RenderTrapezoids.cpp | 372 + nxcomp/src/RenderTrapezoids.h | 88 + nxcomp/src/RenderTriangles.cpp | 362 + nxcomp/src/RenderTriangles.h | 88 + nxcomp/src/Rgb.cpp | 106 + nxcomp/src/Rgb.h | 36 + nxcomp/src/Rle.cpp | 106 + nxcomp/src/Rle.h | 36 + nxcomp/src/SendEvent.cpp | 304 + nxcomp/src/SendEvent.h | 195 + nxcomp/src/SequenceQueue.cpp | 174 + nxcomp/src/SequenceQueue.h | 91 + nxcomp/src/ServerCache.cpp | 195 + nxcomp/src/ServerCache.h | 303 + nxcomp/src/ServerChannel.cpp | 7946 ++++++++++++++ nxcomp/src/ServerChannel.h | 529 + nxcomp/src/ServerProxy.cpp | 621 ++ nxcomp/src/ServerProxy.h | 154 + nxcomp/src/ServerReadBuffer.cpp | 247 + nxcomp/src/ServerReadBuffer.h | 73 + nxcomp/src/ServerStore.cpp | 183 + nxcomp/src/ServerStore.h | 83 + nxcomp/src/SetClipRectangles.cpp | 154 + nxcomp/src/SetClipRectangles.h | 187 + nxcomp/src/SetUnpackAlpha.cpp | 266 + nxcomp/src/SetUnpackAlpha.h | 162 + nxcomp/src/SetUnpackColormap.cpp | 266 + nxcomp/src/SetUnpackColormap.h | 162 + nxcomp/src/SetUnpackGeometry.cpp | 305 + nxcomp/src/SetUnpackGeometry.h | 167 + nxcomp/src/ShapeExtension.cpp | 305 + nxcomp/src/ShapeExtension.h | 164 + nxcomp/src/Socket.cpp | 757 ++ nxcomp/src/Socket.h | 96 + nxcomp/src/Split.cpp | 1839 ++++ nxcomp/src/Split.h | 543 + nxcomp/src/StaticCompressor.cpp | 432 + nxcomp/src/StaticCompressor.h | 80 + nxcomp/src/Statistics.cpp | 2007 ++++ nxcomp/src/Statistics.h | 745 ++ nxcomp/src/Timestamp.cpp | 77 + nxcomp/src/Timestamp.h | 307 + nxcomp/src/TranslateCoords.cpp | 115 + nxcomp/src/TranslateCoords.h | 185 + nxcomp/src/Transport.cpp | 3068 ++++++ nxcomp/src/Transport.h | 577 + nxcomp/src/Types.h | 271 + nxcomp/src/Unpack.cpp | 1514 +++ nxcomp/src/Unpack.h | 149 + nxcomp/src/Vars.c | 54 + nxcomp/src/Version.c | 101 + nxcomp/src/WriteBuffer.cpp | 500 + nxcomp/src/WriteBuffer.h | 134 + nxcomp/src/XidCache.cpp | 51 + nxcomp/src/XidCache.h | 49 + nxcomp/src/Z.cpp | 146 + nxcomp/src/Z.h | 37 + nxproxy/src/Makefile.am | 4 +- 478 files changed, 105105 insertions(+), 105414 deletions(-) delete mode 100644 nxcomp/ActionCache.cpp delete mode 100644 nxcomp/ActionCache.h delete mode 100644 nxcomp/Agent.cpp delete mode 100644 nxcomp/Agent.h delete mode 100644 nxcomp/Alpha.cpp delete mode 100644 nxcomp/Alpha.h delete mode 100644 nxcomp/Auth.cpp delete mode 100644 nxcomp/Auth.h delete mode 100644 nxcomp/Bitmap.cpp delete mode 100644 nxcomp/Bitmap.h delete mode 100644 nxcomp/BlockCache.cpp delete mode 100644 nxcomp/BlockCache.h delete mode 100644 nxcomp/BlockCacheSet.cpp delete mode 100644 nxcomp/BlockCacheSet.h delete mode 100644 nxcomp/ChangeGC.cpp delete mode 100644 nxcomp/ChangeGC.h delete mode 100644 nxcomp/ChangeProperty.cpp delete mode 100644 nxcomp/ChangeProperty.h delete mode 100644 nxcomp/Channel.cpp delete mode 100644 nxcomp/Channel.h delete mode 100644 nxcomp/ChannelCache.cpp delete mode 100644 nxcomp/ChannelCache.h delete mode 100644 nxcomp/ChannelEndPoint.cpp delete mode 100644 nxcomp/ChannelEndPoint.h delete mode 100644 nxcomp/ChannelStore.h delete mode 100644 nxcomp/CharCache.cpp delete mode 100644 nxcomp/CharCache.h delete mode 100644 nxcomp/Children.cpp delete mode 100644 nxcomp/ClearArea.cpp delete mode 100644 nxcomp/ClearArea.h delete mode 100644 nxcomp/ClientCache.cpp delete mode 100644 nxcomp/ClientCache.h delete mode 100644 nxcomp/ClientChannel.cpp delete mode 100644 nxcomp/ClientChannel.h delete mode 100644 nxcomp/ClientProxy.cpp delete mode 100644 nxcomp/ClientProxy.h delete mode 100644 nxcomp/ClientReadBuffer.cpp delete mode 100644 nxcomp/ClientReadBuffer.h delete mode 100644 nxcomp/ClientStore.cpp delete mode 100644 nxcomp/ClientStore.h delete mode 100644 nxcomp/Colormap.cpp delete mode 100644 nxcomp/Colormap.h delete mode 100644 nxcomp/ConfigureWindow.cpp delete mode 100644 nxcomp/ConfigureWindow.h delete mode 100644 nxcomp/Control.cpp delete mode 100644 nxcomp/Control.h delete mode 100644 nxcomp/CopyArea.cpp delete mode 100644 nxcomp/CopyArea.h delete mode 100644 nxcomp/CreateGC.cpp delete mode 100644 nxcomp/CreateGC.h delete mode 100644 nxcomp/CreatePixmap.cpp delete mode 100644 nxcomp/CreatePixmap.h delete mode 100644 nxcomp/DecodeBuffer.cpp delete mode 100644 nxcomp/DecodeBuffer.h delete mode 100644 nxcomp/EncodeBuffer.cpp delete mode 100644 nxcomp/EncodeBuffer.h delete mode 100644 nxcomp/FillPoly.cpp delete mode 100644 nxcomp/FillPoly.h delete mode 100644 nxcomp/Fork.cpp delete mode 100644 nxcomp/Fork.h delete mode 100644 nxcomp/FreeCache.h delete mode 100644 nxcomp/GenericChannel.cpp delete mode 100644 nxcomp/GenericChannel.h delete mode 100644 nxcomp/GenericReadBuffer.cpp delete mode 100644 nxcomp/GenericReadBuffer.h delete mode 100644 nxcomp/GenericReply.cpp delete mode 100644 nxcomp/GenericReply.h delete mode 100644 nxcomp/GenericRequest.cpp delete mode 100644 nxcomp/GenericRequest.h delete mode 100644 nxcomp/GetImage.cpp delete mode 100644 nxcomp/GetImage.h delete mode 100644 nxcomp/GetImageReply.cpp delete mode 100644 nxcomp/GetImageReply.h delete mode 100644 nxcomp/GetProperty.cpp delete mode 100644 nxcomp/GetProperty.h delete mode 100644 nxcomp/GetPropertyReply.cpp delete mode 100644 nxcomp/GetPropertyReply.h delete mode 100644 nxcomp/ImageText16.cpp delete mode 100644 nxcomp/ImageText16.h delete mode 100644 nxcomp/ImageText8.cpp delete mode 100644 nxcomp/ImageText8.h delete mode 100644 nxcomp/IntCache.cpp delete mode 100644 nxcomp/IntCache.h delete mode 100644 nxcomp/InternAtom.cpp delete mode 100644 nxcomp/InternAtom.h delete mode 100644 nxcomp/Jpeg.cpp delete mode 100644 nxcomp/Jpeg.h delete mode 100644 nxcomp/Keeper.cpp delete mode 100644 nxcomp/Keeper.h delete mode 100644 nxcomp/List.cpp delete mode 100644 nxcomp/List.h delete mode 100644 nxcomp/ListFontsReply.cpp delete mode 100644 nxcomp/ListFontsReply.h delete mode 100644 nxcomp/Loop.cpp delete mode 100644 nxcomp/MD5.c delete mode 100644 nxcomp/MD5.h create mode 100644 nxcomp/Makefile.am delete mode 100644 nxcomp/Makefile.in delete mode 100644 nxcomp/Message.cpp delete mode 100644 nxcomp/Message.h delete mode 100644 nxcomp/Misc.cpp delete mode 100644 nxcomp/Misc.h delete mode 100644 nxcomp/NX.h delete mode 100644 nxcomp/NXalert.h delete mode 100644 nxcomp/NXmitshm.h delete mode 100644 nxcomp/NXpack.h delete mode 100644 nxcomp/NXproto.h delete mode 100644 nxcomp/NXrender.h delete mode 100644 nxcomp/NXvars.h delete mode 100644 nxcomp/OpcodeCache.h delete mode 100644 nxcomp/OpcodeStore.cpp delete mode 100644 nxcomp/OpcodeStore.h delete mode 100644 nxcomp/Pack.c delete mode 100644 nxcomp/Pgn.cpp delete mode 100644 nxcomp/Pgn.h delete mode 100644 nxcomp/Pipe.cpp delete mode 100644 nxcomp/Pipe.h delete mode 100644 nxcomp/PolyArc.cpp delete mode 100644 nxcomp/PolyArc.h delete mode 100644 nxcomp/PolyFillArc.cpp delete mode 100644 nxcomp/PolyFillArc.h delete mode 100644 nxcomp/PolyFillRectangle.cpp delete mode 100644 nxcomp/PolyFillRectangle.h delete mode 100644 nxcomp/PolyLine.cpp delete mode 100644 nxcomp/PolyLine.h delete mode 100644 nxcomp/PolyPoint.cpp delete mode 100644 nxcomp/PolyPoint.h delete mode 100644 nxcomp/PolySegment.cpp delete mode 100644 nxcomp/PolySegment.h delete mode 100644 nxcomp/PolyText16.cpp delete mode 100644 nxcomp/PolyText16.h delete mode 100644 nxcomp/PolyText8.cpp delete mode 100644 nxcomp/PolyText8.h delete mode 100644 nxcomp/Proxy.cpp delete mode 100644 nxcomp/Proxy.h delete mode 100644 nxcomp/ProxyReadBuffer.cpp delete mode 100644 nxcomp/ProxyReadBuffer.h delete mode 100644 nxcomp/PutImage.cpp delete mode 100644 nxcomp/PutImage.h delete mode 100644 nxcomp/PutPackedImage.cpp delete mode 100644 nxcomp/PutPackedImage.h delete mode 100644 nxcomp/QueryFontReply.cpp delete mode 100644 nxcomp/QueryFontReply.h delete mode 100644 nxcomp/ReadBuffer.cpp delete mode 100644 nxcomp/ReadBuffer.h delete mode 100644 nxcomp/RenderAddGlyphs.cpp delete mode 100644 nxcomp/RenderAddGlyphs.h delete mode 100644 nxcomp/RenderChangePicture.cpp delete mode 100644 nxcomp/RenderChangePicture.h delete mode 100644 nxcomp/RenderComposite.cpp delete mode 100644 nxcomp/RenderComposite.h delete mode 100644 nxcomp/RenderCompositeGlyphs.cpp delete mode 100644 nxcomp/RenderCompositeGlyphs.h delete mode 100644 nxcomp/RenderCreateGlyphSet.cpp delete mode 100644 nxcomp/RenderCreateGlyphSet.h delete mode 100644 nxcomp/RenderCreatePicture.cpp delete mode 100644 nxcomp/RenderCreatePicture.h delete mode 100644 nxcomp/RenderExtension.cpp delete mode 100644 nxcomp/RenderExtension.h delete mode 100644 nxcomp/RenderFillRectangles.cpp delete mode 100644 nxcomp/RenderFillRectangles.h delete mode 100644 nxcomp/RenderFreeGlyphSet.cpp delete mode 100644 nxcomp/RenderFreeGlyphSet.h delete mode 100644 nxcomp/RenderFreePicture.cpp delete mode 100644 nxcomp/RenderFreePicture.h delete mode 100644 nxcomp/RenderGenericRequest.cpp delete mode 100644 nxcomp/RenderGenericRequest.h delete mode 100644 nxcomp/RenderMinorExtensionHeaders.h delete mode 100644 nxcomp/RenderMinorExtensionMethods.h delete mode 100644 nxcomp/RenderMinorExtensionTags.h delete mode 100644 nxcomp/RenderPictureClip.cpp delete mode 100644 nxcomp/RenderPictureClip.h delete mode 100644 nxcomp/RenderPictureFilter.cpp delete mode 100644 nxcomp/RenderPictureFilter.h delete mode 100644 nxcomp/RenderPictureTransform.cpp delete mode 100644 nxcomp/RenderPictureTransform.h delete mode 100644 nxcomp/RenderTrapezoids.cpp delete mode 100644 nxcomp/RenderTrapezoids.h delete mode 100644 nxcomp/RenderTriangles.cpp delete mode 100644 nxcomp/RenderTriangles.h delete mode 100644 nxcomp/Rgb.cpp delete mode 100644 nxcomp/Rgb.h delete mode 100644 nxcomp/Rle.cpp delete mode 100644 nxcomp/Rle.h delete mode 100644 nxcomp/SendEvent.cpp delete mode 100644 nxcomp/SendEvent.h delete mode 100644 nxcomp/SequenceQueue.cpp delete mode 100644 nxcomp/SequenceQueue.h delete mode 100644 nxcomp/ServerCache.cpp delete mode 100644 nxcomp/ServerCache.h delete mode 100644 nxcomp/ServerChannel.cpp delete mode 100644 nxcomp/ServerChannel.h delete mode 100644 nxcomp/ServerProxy.cpp delete mode 100644 nxcomp/ServerProxy.h delete mode 100644 nxcomp/ServerReadBuffer.cpp delete mode 100644 nxcomp/ServerReadBuffer.h delete mode 100644 nxcomp/ServerStore.cpp delete mode 100644 nxcomp/ServerStore.h delete mode 100644 nxcomp/SetClipRectangles.cpp delete mode 100644 nxcomp/SetClipRectangles.h delete mode 100644 nxcomp/SetUnpackAlpha.cpp delete mode 100644 nxcomp/SetUnpackAlpha.h delete mode 100644 nxcomp/SetUnpackColormap.cpp delete mode 100644 nxcomp/SetUnpackColormap.h delete mode 100644 nxcomp/SetUnpackGeometry.cpp delete mode 100644 nxcomp/SetUnpackGeometry.h delete mode 100644 nxcomp/ShapeExtension.cpp delete mode 100644 nxcomp/ShapeExtension.h delete mode 100644 nxcomp/Socket.cpp delete mode 100644 nxcomp/Socket.h delete mode 100644 nxcomp/Split.cpp delete mode 100644 nxcomp/Split.h delete mode 100644 nxcomp/StaticCompressor.cpp delete mode 100644 nxcomp/StaticCompressor.h delete mode 100644 nxcomp/Statistics.cpp delete mode 100644 nxcomp/Statistics.h delete mode 100644 nxcomp/Timestamp.cpp delete mode 100644 nxcomp/Timestamp.h delete mode 100644 nxcomp/TranslateCoords.cpp delete mode 100644 nxcomp/TranslateCoords.h delete mode 100644 nxcomp/Transport.cpp delete mode 100644 nxcomp/Transport.h delete mode 100644 nxcomp/Types.h delete mode 100644 nxcomp/Unpack.cpp delete mode 100644 nxcomp/Unpack.h delete mode 100644 nxcomp/Vars.c delete mode 100644 nxcomp/Version.c delete mode 100644 nxcomp/WriteBuffer.cpp delete mode 100644 nxcomp/WriteBuffer.h delete mode 100644 nxcomp/XidCache.cpp delete mode 100644 nxcomp/XidCache.h delete mode 100644 nxcomp/Z.cpp delete mode 100644 nxcomp/Z.h create mode 100644 nxcomp/configure.ac delete mode 100644 nxcomp/configure.in create mode 100644 nxcomp/include/MD5.h create mode 100644 nxcomp/include/NX.h create mode 100644 nxcomp/include/NXalert.h create mode 100644 nxcomp/include/NXpack.h create mode 100644 nxcomp/include/NXproto.h create mode 100644 nxcomp/include/NXvars.h delete mode 100755 nxcomp/install-sh create mode 120000 nxcomp/m4/nx-macros.m4 delete mode 100755 nxcomp/mkinstalldirs create mode 100644 nxcomp/src/ActionCache.cpp create mode 100644 nxcomp/src/ActionCache.h create mode 100644 nxcomp/src/Agent.cpp create mode 100644 nxcomp/src/Agent.h create mode 100644 nxcomp/src/Alpha.cpp create mode 100644 nxcomp/src/Alpha.h create mode 100644 nxcomp/src/Auth.cpp create mode 100644 nxcomp/src/Auth.h create mode 100644 nxcomp/src/Bitmap.cpp create mode 100644 nxcomp/src/Bitmap.h create mode 100644 nxcomp/src/BlockCache.cpp create mode 100644 nxcomp/src/BlockCache.h create mode 100644 nxcomp/src/BlockCacheSet.cpp create mode 100644 nxcomp/src/BlockCacheSet.h create mode 100644 nxcomp/src/ChangeGC.cpp create mode 100644 nxcomp/src/ChangeGC.h create mode 100644 nxcomp/src/ChangeProperty.cpp create mode 100644 nxcomp/src/ChangeProperty.h create mode 100644 nxcomp/src/Channel.cpp create mode 100644 nxcomp/src/Channel.h create mode 100644 nxcomp/src/ChannelCache.cpp create mode 100644 nxcomp/src/ChannelCache.h create mode 100644 nxcomp/src/ChannelEndPoint.cpp create mode 100644 nxcomp/src/ChannelEndPoint.h create mode 100644 nxcomp/src/ChannelStore.h create mode 100644 nxcomp/src/CharCache.cpp create mode 100644 nxcomp/src/CharCache.h create mode 100644 nxcomp/src/Children.cpp create mode 100644 nxcomp/src/ClearArea.cpp create mode 100644 nxcomp/src/ClearArea.h create mode 100644 nxcomp/src/ClientCache.cpp create mode 100644 nxcomp/src/ClientCache.h create mode 100644 nxcomp/src/ClientChannel.cpp create mode 100644 nxcomp/src/ClientChannel.h create mode 100644 nxcomp/src/ClientProxy.cpp create mode 100644 nxcomp/src/ClientProxy.h create mode 100644 nxcomp/src/ClientReadBuffer.cpp create mode 100644 nxcomp/src/ClientReadBuffer.h create mode 100644 nxcomp/src/ClientStore.cpp create mode 100644 nxcomp/src/ClientStore.h create mode 100644 nxcomp/src/Colormap.cpp create mode 100644 nxcomp/src/Colormap.h create mode 100644 nxcomp/src/ConfigureWindow.cpp create mode 100644 nxcomp/src/ConfigureWindow.h create mode 100644 nxcomp/src/Control.cpp create mode 100644 nxcomp/src/Control.h create mode 100644 nxcomp/src/CopyArea.cpp create mode 100644 nxcomp/src/CopyArea.h create mode 100644 nxcomp/src/CreateGC.cpp create mode 100644 nxcomp/src/CreateGC.h create mode 100644 nxcomp/src/CreatePixmap.cpp create mode 100644 nxcomp/src/CreatePixmap.h create mode 100644 nxcomp/src/DecodeBuffer.cpp create mode 100644 nxcomp/src/DecodeBuffer.h create mode 100644 nxcomp/src/EncodeBuffer.cpp create mode 100644 nxcomp/src/EncodeBuffer.h create mode 100644 nxcomp/src/FillPoly.cpp create mode 100644 nxcomp/src/FillPoly.h create mode 100644 nxcomp/src/Fork.cpp create mode 100644 nxcomp/src/Fork.h create mode 100644 nxcomp/src/FreeCache.h create mode 100644 nxcomp/src/GenericChannel.cpp create mode 100644 nxcomp/src/GenericChannel.h create mode 100644 nxcomp/src/GenericReadBuffer.cpp create mode 100644 nxcomp/src/GenericReadBuffer.h create mode 100644 nxcomp/src/GenericReply.cpp create mode 100644 nxcomp/src/GenericReply.h create mode 100644 nxcomp/src/GenericRequest.cpp create mode 100644 nxcomp/src/GenericRequest.h create mode 100644 nxcomp/src/GetImage.cpp create mode 100644 nxcomp/src/GetImage.h create mode 100644 nxcomp/src/GetImageReply.cpp create mode 100644 nxcomp/src/GetImageReply.h create mode 100644 nxcomp/src/GetProperty.cpp create mode 100644 nxcomp/src/GetProperty.h create mode 100644 nxcomp/src/GetPropertyReply.cpp create mode 100644 nxcomp/src/GetPropertyReply.h create mode 100644 nxcomp/src/ImageText16.cpp create mode 100644 nxcomp/src/ImageText16.h create mode 100644 nxcomp/src/ImageText8.cpp create mode 100644 nxcomp/src/ImageText8.h create mode 100644 nxcomp/src/IntCache.cpp create mode 100644 nxcomp/src/IntCache.h create mode 100644 nxcomp/src/InternAtom.cpp create mode 100644 nxcomp/src/InternAtom.h create mode 100644 nxcomp/src/Jpeg.cpp create mode 100644 nxcomp/src/Jpeg.h create mode 100644 nxcomp/src/Keeper.cpp create mode 100644 nxcomp/src/Keeper.h create mode 100644 nxcomp/src/List.cpp create mode 100644 nxcomp/src/List.h create mode 100644 nxcomp/src/ListFontsReply.cpp create mode 100644 nxcomp/src/ListFontsReply.h create mode 100644 nxcomp/src/Loop.cpp create mode 100644 nxcomp/src/MD5.c create mode 100644 nxcomp/src/Makefile.am create mode 100644 nxcomp/src/Message.cpp create mode 100644 nxcomp/src/Message.h create mode 100644 nxcomp/src/Misc.cpp create mode 100644 nxcomp/src/Misc.h create mode 100644 nxcomp/src/NXmitshm.h create mode 100644 nxcomp/src/NXrender.h create mode 100644 nxcomp/src/OpcodeCache.h create mode 100644 nxcomp/src/OpcodeStore.cpp create mode 100644 nxcomp/src/OpcodeStore.h create mode 100644 nxcomp/src/Pack.c create mode 100644 nxcomp/src/Pgn.cpp create mode 100644 nxcomp/src/Pgn.h create mode 100644 nxcomp/src/Pipe.cpp create mode 100644 nxcomp/src/Pipe.h create mode 100644 nxcomp/src/PolyArc.cpp create mode 100644 nxcomp/src/PolyArc.h create mode 100644 nxcomp/src/PolyFillArc.cpp create mode 100644 nxcomp/src/PolyFillArc.h create mode 100644 nxcomp/src/PolyFillRectangle.cpp create mode 100644 nxcomp/src/PolyFillRectangle.h create mode 100644 nxcomp/src/PolyLine.cpp create mode 100644 nxcomp/src/PolyLine.h create mode 100644 nxcomp/src/PolyPoint.cpp create mode 100644 nxcomp/src/PolyPoint.h create mode 100644 nxcomp/src/PolySegment.cpp create mode 100644 nxcomp/src/PolySegment.h create mode 100644 nxcomp/src/PolyText16.cpp create mode 100644 nxcomp/src/PolyText16.h create mode 100644 nxcomp/src/PolyText8.cpp create mode 100644 nxcomp/src/PolyText8.h create mode 100644 nxcomp/src/Proxy.cpp create mode 100644 nxcomp/src/Proxy.h create mode 100644 nxcomp/src/ProxyReadBuffer.cpp create mode 100644 nxcomp/src/ProxyReadBuffer.h create mode 100644 nxcomp/src/PutImage.cpp create mode 100644 nxcomp/src/PutImage.h create mode 100644 nxcomp/src/PutPackedImage.cpp create mode 100644 nxcomp/src/PutPackedImage.h create mode 100644 nxcomp/src/QueryFontReply.cpp create mode 100644 nxcomp/src/QueryFontReply.h create mode 100644 nxcomp/src/ReadBuffer.cpp create mode 100644 nxcomp/src/ReadBuffer.h create mode 100644 nxcomp/src/RenderAddGlyphs.cpp create mode 100644 nxcomp/src/RenderAddGlyphs.h create mode 100644 nxcomp/src/RenderChangePicture.cpp create mode 100644 nxcomp/src/RenderChangePicture.h create mode 100644 nxcomp/src/RenderComposite.cpp create mode 100644 nxcomp/src/RenderComposite.h create mode 100644 nxcomp/src/RenderCompositeGlyphs.cpp create mode 100644 nxcomp/src/RenderCompositeGlyphs.h create mode 100644 nxcomp/src/RenderCreateGlyphSet.cpp create mode 100644 nxcomp/src/RenderCreateGlyphSet.h create mode 100644 nxcomp/src/RenderCreatePicture.cpp create mode 100644 nxcomp/src/RenderCreatePicture.h create mode 100644 nxcomp/src/RenderExtension.cpp create mode 100644 nxcomp/src/RenderExtension.h create mode 100644 nxcomp/src/RenderFillRectangles.cpp create mode 100644 nxcomp/src/RenderFillRectangles.h create mode 100644 nxcomp/src/RenderFreeGlyphSet.cpp create mode 100644 nxcomp/src/RenderFreeGlyphSet.h create mode 100644 nxcomp/src/RenderFreePicture.cpp create mode 100644 nxcomp/src/RenderFreePicture.h create mode 100644 nxcomp/src/RenderGenericRequest.cpp create mode 100644 nxcomp/src/RenderGenericRequest.h create mode 100644 nxcomp/src/RenderMinorExtensionHeaders.h create mode 100644 nxcomp/src/RenderMinorExtensionMethods.h create mode 100644 nxcomp/src/RenderMinorExtensionTags.h create mode 100644 nxcomp/src/RenderPictureClip.cpp create mode 100644 nxcomp/src/RenderPictureClip.h create mode 100644 nxcomp/src/RenderPictureFilter.cpp create mode 100644 nxcomp/src/RenderPictureFilter.h create mode 100644 nxcomp/src/RenderPictureTransform.cpp create mode 100644 nxcomp/src/RenderPictureTransform.h create mode 100644 nxcomp/src/RenderTrapezoids.cpp create mode 100644 nxcomp/src/RenderTrapezoids.h create mode 100644 nxcomp/src/RenderTriangles.cpp create mode 100644 nxcomp/src/RenderTriangles.h create mode 100644 nxcomp/src/Rgb.cpp create mode 100644 nxcomp/src/Rgb.h create mode 100644 nxcomp/src/Rle.cpp create mode 100644 nxcomp/src/Rle.h create mode 100644 nxcomp/src/SendEvent.cpp create mode 100644 nxcomp/src/SendEvent.h create mode 100644 nxcomp/src/SequenceQueue.cpp create mode 100644 nxcomp/src/SequenceQueue.h create mode 100644 nxcomp/src/ServerCache.cpp create mode 100644 nxcomp/src/ServerCache.h create mode 100644 nxcomp/src/ServerChannel.cpp create mode 100644 nxcomp/src/ServerChannel.h create mode 100644 nxcomp/src/ServerProxy.cpp create mode 100644 nxcomp/src/ServerProxy.h create mode 100644 nxcomp/src/ServerReadBuffer.cpp create mode 100644 nxcomp/src/ServerReadBuffer.h create mode 100644 nxcomp/src/ServerStore.cpp create mode 100644 nxcomp/src/ServerStore.h create mode 100644 nxcomp/src/SetClipRectangles.cpp create mode 100644 nxcomp/src/SetClipRectangles.h create mode 100644 nxcomp/src/SetUnpackAlpha.cpp create mode 100644 nxcomp/src/SetUnpackAlpha.h create mode 100644 nxcomp/src/SetUnpackColormap.cpp create mode 100644 nxcomp/src/SetUnpackColormap.h create mode 100644 nxcomp/src/SetUnpackGeometry.cpp create mode 100644 nxcomp/src/SetUnpackGeometry.h create mode 100644 nxcomp/src/ShapeExtension.cpp create mode 100644 nxcomp/src/ShapeExtension.h create mode 100644 nxcomp/src/Socket.cpp create mode 100644 nxcomp/src/Socket.h create mode 100644 nxcomp/src/Split.cpp create mode 100644 nxcomp/src/Split.h create mode 100644 nxcomp/src/StaticCompressor.cpp create mode 100644 nxcomp/src/StaticCompressor.h create mode 100644 nxcomp/src/Statistics.cpp create mode 100644 nxcomp/src/Statistics.h create mode 100644 nxcomp/src/Timestamp.cpp create mode 100644 nxcomp/src/Timestamp.h create mode 100644 nxcomp/src/TranslateCoords.cpp create mode 100644 nxcomp/src/TranslateCoords.h create mode 100644 nxcomp/src/Transport.cpp create mode 100644 nxcomp/src/Transport.h create mode 100644 nxcomp/src/Types.h create mode 100644 nxcomp/src/Unpack.cpp create mode 100644 nxcomp/src/Unpack.h create mode 100644 nxcomp/src/Vars.c create mode 100644 nxcomp/src/Version.c create mode 100644 nxcomp/src/WriteBuffer.cpp create mode 100644 nxcomp/src/WriteBuffer.h create mode 100644 nxcomp/src/XidCache.cpp create mode 100644 nxcomp/src/XidCache.h create mode 100644 nxcomp/src/Z.cpp create mode 100644 nxcomp/src/Z.h diff --git a/Makefile b/Makefile index d38015a00..2b4e5dfbd 100644 --- a/Makefile +++ b/Makefile @@ -54,14 +54,7 @@ all: test: echo "No testing for NX (redistributed)" -build-lite: - cd nxcomp && autoconf && (${CONFIGURE}) && ${MAKE} - cd nxproxy && autoreconf -vfsi && (${CONFIGURE}) && ${MAKE} - -build-full: -# in the full case, we rely on "magic" in the nx-X11 imake-based makefiles... - cd nxcomp && autoconf && (${CONFIGURE}) && ${MAKE} - +build-env: # prepare nx-X11/config/cf/nxversion.def sed \ -e 's/###NX_VERSION_MAJOR###/$(NX_VERSION_MAJOR)/' \ @@ -74,6 +67,13 @@ build-full: # prepare Makefiles and the nx-X11 symlinking magic cd nx-X11 && make BuildEnv FONT_DEFINES=$(FONT_DEFINES) +build-lite: + cd nxcomp && autoreconf -vfsi && (${CONFIGURE}) && ${MAKE} + cd nxproxy && autoreconf -vfsi && (${CONFIGURE}) && ${MAKE} + +build-full: build-env +# in the full case, we rely on "magic" in the nx-X11 imake-based makefiles... + cd nxcomp && autoreconf -vfsi && (${CONFIGURE}) && ${MAKE} # build libNX_X11 and libNX_Xext prior to building # nxcomp{ext,shad}. cd nx-X11/lib && make diff --git a/debian/libxcomp-dev.install b/debian/libxcomp-dev.install index e27e6ecf0..f73422f40 100644 --- a/debian/libxcomp-dev.install +++ b/debian/libxcomp-dev.install @@ -1,4 +1,5 @@ usr/lib/*/libXcomp.so +usr/lib/*/libXcomp.a usr/include/*/nx/NX.h usr/include/*/nx/NXalert.h usr/include/*/nx/NXpack.h diff --git a/debian/rules b/debian/rules index b59ba83a5..13490a86c 100755 --- a/debian/rules +++ b/debian/rules @@ -24,7 +24,7 @@ override_dh_clean: override_dh_install: # remove static libs - rm debian/tmp/usr/lib/$(DEB_BUILD_MULTIARCH)/libXcomp.a + rm debian/tmp/usr/lib/$(DEB_BUILD_MULTIARCH)/libXcomp.la rm debian/tmp/usr/lib/$(DEB_BUILD_MULTIARCH)/libXcompshad.la # remove extras, GL, and other unneeded headers diff --git a/nx-X11/lib/X11/Imakefile b/nx-X11/lib/X11/Imakefile index 5b289fae8..a6471bff1 100644 --- a/nx-X11/lib/X11/Imakefile +++ b/nx-X11/lib/X11/Imakefile @@ -36,9 +36,9 @@ BuildIncludes($(HEADERS),IncSubdir,..) #if NXLibraries #ifdef SunArchitecture -NX_INCLUDES = -I../../../nxcomp -I/usr/sfw/include +NX_INCLUDES = -I../../../nxcomp/include -I/usr/sfw/include #else -NX_INCLUDES = -I../../../nxcomp +NX_INCLUDES = -I../../../nxcomp/include #endif NX_DEFINES = -DNX_TRANS_SOCKET \ @@ -81,7 +81,7 @@ NX_XCOMPLIBNAME = libXcomp.so NX_XCOMPEXTLIBNAME = libXcompext.so #endif -NX_XCOMPLIBDIR = $(XTOP)/../nxcomp +NX_XCOMPLIBDIR = $(XTOP)/../nxcomp/src/.libs NX_XCOMPLIBLINK = Xcomp NX_XCOMPLIBTARGET = $(NX_XCOMPLIBDIR)/$(NX_XCOMPLIBNAME) NX_REQUIREDLIBS = -L$(NX_XCOMPLIBDIR) -l$(NX_XCOMPLIBLINK) diff --git a/nx-X11/programs/Xserver/Imakefile b/nx-X11/programs/Xserver/Imakefile index ed49313ee..3c7e68597 100644 --- a/nx-X11/programs/Xserver/Imakefile +++ b/nx-X11/programs/Xserver/Imakefile @@ -213,12 +213,12 @@ NXAGENTDDXDIR = hw NXAGENTDIRS = $(STDDIRS) $(FBDIR) $(MIDAMAGEDIR) $(NXAGENTDDXDIR) $(DEPDIRS) NX_XCOMP_HEADERS = \ - ../../../nxcomp/MD5.h \ - ../../../nxcomp/NXalert.h \ - ../../../nxcomp/NX.h \ - ../../../nxcomp/NXpack.h \ - ../../../nxcomp/NXproto.h \ - ../../../nxcomp/NXvars.h \ + ../../../nxcomp/include/MD5.h \ + ../../../nxcomp/include/NXalert.h \ + ../../../nxcomp/include/NX.h \ + ../../../nxcomp/include/NXpack.h \ + ../../../nxcomp/include/NXproto.h \ + ../../../nxcomp/include/NXvars.h \ $(NULL) NX_XCOMPSHAD_HEADERS = \ @@ -315,7 +315,7 @@ $(NXAGENTOBJS) $(NXAGENTLIBS) $(NXAGENTSYSLIBS):: $(NXAGENTDIRS) #if defined(SunArchitecture) NXAGENTNXLIBS = -L/usr/sfw/lib \ - -L../../../nxcomp \ + -L../../../nxcomp/src/.libs \ -L../../../nxcompshad/src/.libs \ -lrt \ -lXcomp \ @@ -330,7 +330,7 @@ NXAGENTNXLIBS = -L/usr/sfw/lib \ -lXext \ $(NULL) #elif defined(cygwinArchitecture) -NXAGENTNXLIBS = -L../../../nxcomp \ +NXAGENTNXLIBS = -L../../../nxcomp/src/.libs \ -L../../../nxcompshad/src/.libs \ -lXcomp \ -lXcompshad \ @@ -343,7 +343,7 @@ NXAGENTNXLIBS = -L../../../nxcomp \ -lXext \ $(NULL) #elif defined(OpenBSDArchitecture) -NXAGENTNXLIBS = -L../../../nxcomp \ +NXAGENTNXLIBS = -L../../../nxcomp/src/.libs \ -L../../../nx-X11/exports/lib \ -L../../../nxcompshad/src/.libs \ -lkvm \ @@ -359,7 +359,7 @@ NXAGENTNXLIBS = -L../../../nxcomp \ -lXext \ $(NULL) #else -NXAGENTNXLIBS = -L../../../nxcomp \ +NXAGENTNXLIBS = -L../../../nxcomp/src/.libs \ -L../../../nxcompshad/src/.libs \ -lXcomp \ -lXcompshad \ diff --git a/nxcomp/.gitignore b/nxcomp/.gitignore index 27a99e5b2..a148dfa93 100644 --- a/nxcomp/.gitignore +++ b/nxcomp/.gitignore @@ -1,2 +1,23 @@ -nxcomp.pc Makefile +Makefile.in +aclocal.m4 +compile +config.guess +config.sub +depcomp +install-sh +ltmain.sh +missing +config.h +config.h.in +libtool +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +nxcomp.pc +src/.deps/ +src/Makefile +src/Makefile.in +stamp-h1 diff --git a/nxcomp/ActionCache.cpp b/nxcomp/ActionCache.cpp deleted file mode 100644 index 8ad7f7ba2..000000000 --- a/nxcomp/ActionCache.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Control.h" - -#include "ActionCache.h" - -ActionCache::ActionCache() -{ - for (int i = 0; i < 256; i++) - { - base_[i] = new IntCache(8); - } - - slot_ = 0; - last_ = 0; -} - -ActionCache::~ActionCache() -{ - for (int i = 0; i < 256; i++) - { - delete base_[i]; - } -} diff --git a/nxcomp/ActionCache.h b/nxcomp/ActionCache.h deleted file mode 100644 index 2aedd4a07..000000000 --- a/nxcomp/ActionCache.h +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ActionCache_H -#define ActionCache_H - -#include "IntCache.h" - -class ActionCache -{ - friend class EncodeBuffer; - friend class DecodeBuffer; - - public: - - ActionCache(); - ~ActionCache(); - - private: - - IntCache *base_[256]; - - unsigned int slot_; - unsigned short last_; -}; - -#endif /* ActionCache_H */ diff --git a/nxcomp/Agent.cpp b/nxcomp/Agent.cpp deleted file mode 100644 index cd65101b3..000000000 --- a/nxcomp/Agent.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "Agent.h" -#include "Proxy.h" - -extern Proxy *proxy; - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -Agent::Agent(int fd[2]) -{ - remoteFd_ = fd[0]; - localFd_ = fd[1]; - - transport_ = new AgentTransport(localFd_); - - if (transport_ == NULL) - { - #ifdef PANIC - *logofs << "Agent: PANIC! Can't create the memory-to-memory transport " - << "for FD#" << localFd_ << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't create the memory-to-memory transport " - << "for FD#" << localFd_ << ".\n"; - - HandleCleanup(); - } - - FD_ZERO(&saveRead_); - FD_ZERO(&saveWrite_); - - canRead_ = 0; - - #ifdef DEBUG - *logofs << "Agent: Created agent object at " << this - << ".\n" << logofs_flush; - #endif -} - -Agent::~Agent() -{ - delete transport_; - - #ifdef DEBUG - *logofs << "Agent: Deleted agent object at " << this - << ".\n" << logofs_flush; - #endif -} diff --git a/nxcomp/Agent.h b/nxcomp/Agent.h deleted file mode 100644 index 3e1a50ae5..000000000 --- a/nxcomp/Agent.h +++ /dev/null @@ -1,263 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Agent_H -#define Agent_H - -#include - -#include -#include -#include - -#include "Misc.h" -#include "Transport.h" -#include "Proxy.h" - -extern Proxy *proxy; - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -class Agent -{ - public: - - // - // Must be created by passing the fake descriptor that - // will be used for simulating socket communication - // betwen the agent and the proxy. I/O will take place - // by copying data to the agent's read and write buf- - // fers. - // - - Agent(int fd[2]); - - ~Agent(); - - AgentTransport *getTransport() const - { - return transport_; - } - - void saveReadMask(fd_set *readSet) - { - saveRead_ = *readSet; - } - - void saveWriteMask(fd_set *writeSet) - { - saveWrite_ = *writeSet; - } - - void clearReadMask(fd_set *readSet) - { - FD_CLR(remoteFd_, readSet); - FD_CLR(localFd_, readSet); - } - - void clearWriteMask(fd_set *writeSet) - { - FD_CLR(remoteFd_, writeSet); - FD_CLR(localFd_, writeSet); - } - - void setLocalRead(fd_set *readSet, int *result) - { - (*result)++; - - FD_SET(localFd_, readSet); - } - - void setRemoteRead(fd_set *readSet, int *result) - { - (*result)++; - - FD_SET(remoteFd_, readSet); - } - - void setRemoteWrite(fd_set *writeSet, int *result) - { - (*result)++; - - FD_SET(remoteFd_, writeSet); - } - - fd_set *getSavedReadMask() - { - return &saveRead_; - } - - fd_set *getSavedWriteMask() - { - return &saveWrite_; - } - - int getRemoteFd() const - { - return remoteFd_; - } - - int getLocalFd() const - { - return localFd_; - } - - int getProxyFd() const - { - return proxy -> getFd(); - } - - int isValid() const - { - return (transport_ != NULL); - } - - int localReadable() - { - return (transport_ -> readable() != 0); - } - - // - // Check if we can process more data from - // the agent descriptor and cache the result - // to avoid multiple calls. This must be - // always called before querying the other - // functions. - // - - void saveChannelState() - { - canRead_ = (proxy != NULL ? proxy -> canRead(localFd_) : 0); - } - - int remoteCanRead(const fd_set * const readSet) - { - // OS X 10.5 requires the second argument to be non-const, so copy readSet. - // It's safe though, as FD_ISSET does not operate on it. - fd_set readWorkSet = *readSet; - - #if defined(TEST) || defined(INFO) - *logofs << "Agent: remoteCanRead() is " << - (FD_ISSET(remoteFd_, &readWorkSet) && transport_ -> dequeuable() != 0) - << " with FD_ISSET() " << (int) FD_ISSET(remoteFd_, &readWorkSet) - << " and dequeuable " << transport_ -> dequeuable() - << ".\n" << logofs_flush; - #endif - - return (FD_ISSET(remoteFd_, &readWorkSet) && - transport_ -> dequeuable() != 0); - } - - int remoteCanWrite(const fd_set * const writeSet) - { - // OS X 10.5 requires the second argument to be non-const, so copy writeSet. - // It's safe though, as FD_ISSET does not operate on it. - fd_set writeWorkSet = *writeSet; - - #if defined(TEST) || defined(INFO) - *logofs << "Agent: remoteCanWrite() is " << - (FD_ISSET(remoteFd_, &writeWorkSet) && transport_ -> - queuable() != 0 && canRead_ == 1) << " with FD_ISSET() " - << (int) FD_ISSET(remoteFd_, &writeWorkSet) << " queueable " - << transport_ -> queuable() << " channel can read " - << canRead_ << ".\n" << logofs_flush; - #endif - - return (FD_ISSET(remoteFd_, &writeWorkSet) && - transport_ -> queuable() != 0 && - canRead_ == 1); - } - - int localCanRead() - { - #if defined(TEST) || defined(INFO) - *logofs << "Agent: localCanRead() is " << - (transport_ -> readable() != 0 && canRead_ == 1) - << " with readable " << transport_ -> readable() - << " channel can read " << canRead_ << ".\n" - << logofs_flush; - #endif - - return (transport_ -> readable() != 0 && - canRead_ == 1); - } - - int proxyCanRead() - { - #if defined(TEST) || defined(INFO) - *logofs << "Agent: proxyCanRead() is " << proxy -> canRead() - << ".\n" << logofs_flush; - #endif - - return (proxy -> canRead()); - } - - int proxyCanRead(const fd_set * const readSet) - { - // OS X 10.5 requires the second argument to be non-const, so copy readSet. - // It's safe though, as FD_ISSET does not operate on it. - fd_set readWorkSet = *readSet; - - #if defined(TEST) || defined(INFO) - *logofs << "Agent: proxyCanRead() is " - << ((int) FD_ISSET(proxy -> getFd(), &readWorkSet)) - << ".\n" << logofs_flush; - #endif - - return (FD_ISSET(proxy -> getFd(), &readWorkSet)); - } - - int enqueueData(const char *data, const int size) const - { - return transport_ -> enqueue(data, size); - } - - int dequeueData(char *data, int size) const - { - return transport_ -> dequeue(data, size); - } - - int dequeuableData() const - { - return transport_ -> dequeuable(); - } - - private: - - int remoteFd_; - int localFd_; - - fd_set saveRead_; - fd_set saveWrite_; - - int canRead_; - - AgentTransport *transport_; -}; - -#endif /* Agent_H */ diff --git a/nxcomp/Alpha.cpp b/nxcomp/Alpha.cpp deleted file mode 100644 index 31a31f7cb..000000000 --- a/nxcomp/Alpha.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "Unpack.h" -#include "Alpha.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -int UnpackAlpha(unsigned char method, unsigned char *src_data, int src_size, - unsigned char *dst_data, int dst_size) -{ - if (*src_data == 0) - { - if (dst_size != src_size - 1) - { - #ifdef TEST - *logofs << "UnpackAlpha: PANIC! Invalid destination size " - << dst_size << " with source " << src_size - << ".\n" << logofs_flush; - #endif - - return -1; - } - - #ifdef TEST - *logofs << "UnpackAlpha: Expanding " << src_size - 1 - << " bytes of plain alpha data.\n" << logofs_flush; - #endif - - memcpy(dst_data, src_data + 1, src_size - 1); - - return 1; - } - - unsigned int check_size = dst_size; - - int result = ZDecompress(&unpackStream, dst_data, &check_size, - src_data + 1, src_size - 1); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "UnpackAlpha: PANIC! Failure decompressing alpha data. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decompressing alpha data. " - << "Error is '" << zError(result) << "'.\n"; - - return -1; - } - else if (check_size != (unsigned int) dst_size) - { - #ifdef PANIC - *logofs << "UnpackAlpha: PANIC! Size mismatch in alpha data. " - << "Resulting size is " << check_size << " with " - << "expected size " << dst_size << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Size mismatch in alpha data. " - << "Resulting size is " << check_size << " with " - << "expected size " << dst_size << ".\n"; - - return -1; - } - - #ifdef TEST - *logofs << "UnpackAlpha: Decompressed " << src_size - 1 - << " bytes to " << dst_size << " bytes of alpha data.\n" - << logofs_flush; - #endif - - return 1; -} - -int UnpackAlpha(T_alpha *alpha, unsigned char *dst_data, - int dst_size, int big_endian) -{ - unsigned int count = dst_size >> 2; - - unsigned int i; - - int shift; - - if (count != alpha -> entries) - { - #ifdef WARNING - *logofs << "UnpackAlpha: WARNING! Not applying the alpha with " - << count << " elements needed and " << alpha -> entries - << " available.\n" << logofs_flush; - #endif - - return 0; - } - - shift = (big_endian == 1 ? 0 : 3); - - for (i = 0; i < count; i++) - { - *(dst_data + shift) = *(alpha -> data + i); - - dst_data += 4; - } - - return 1; -} diff --git a/nxcomp/Alpha.h b/nxcomp/Alpha.h deleted file mode 100644 index ea5068812..000000000 --- a/nxcomp/Alpha.h +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Alpha_H -#define Alpha_H - -int UnpackAlpha(unsigned char method, unsigned char *src_data, int src_size, - unsigned char *dst_data, int dst_size); - -int UnpackAlpha(T_alpha *alpha, unsigned char *dst_data, - int dst_size, int big_endian); - -#endif /* Aplha_H */ diff --git a/nxcomp/Auth.cpp b/nxcomp/Auth.cpp deleted file mode 100644 index bc047aa30..000000000 --- a/nxcomp/Auth.cpp +++ /dev/null @@ -1,667 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Auth.h" - -#include "Misc.h" -#include "Control.h" -#include "Timestamp.h" -#include "Pipe.h" - -#define DEFAULT_STRING_LIMIT 512 - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Store the provided cookie as our 'fake' cookie, then -// read the 'real' cookie from the current X authority -// file. -// - -Auth::Auth(char *display, char *cookie) -{ - display_ = NULL; - - file_ = NULL; - - last_ = nullTimestamp(); - - fakeCookie_ = NULL; - realCookie_ = NULL; - - fakeData_ = NULL; - realData_ = NULL; - - dataSize_ = 0; - - generatedCookie_ = 0; - - if (display == NULL || *display == '\0' || cookie == NULL || - *cookie == '\0' || strlen(cookie) != 32) - { - #ifdef PANIC - *logofs << "Auth: PANIC! Can't create the X authorization data " - << "with cookie '" << cookie << "' and display '" - << display << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't create the X authorization data " - << "with cookie '" << cookie << "' and display '" - << display << "'.\n"; - - return; - } - - #ifdef TEST - *logofs << "Auth: Creating X authorization data with cookie '" - << cookie << "' and display '" << display << "'.\n" - << logofs_flush; - #endif - - // - // Get a local copy of all parameters. - // - - display_ = new char[strlen(display) + 1]; - file_ = new char[DEFAULT_STRING_LIMIT]; - - fakeCookie_ = new char[strlen(cookie) + 1]; - realCookie_ = new char[DEFAULT_STRING_LIMIT]; - - if (display_ == NULL || file_ == NULL || - fakeCookie_ == NULL || realCookie_ == NULL) - { - #ifdef PANIC - *logofs << "Auth: PANIC! Cannot allocate memory for the X " - << "authorization data.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot allocate memory for the X " - << "authorization data.\n"; - - return; - } - - strcpy(display_, display); - - *file_ = '\0'; - - strcpy(fakeCookie_, cookie); - - *realCookie_ = '\0'; - - // - // Get the real cookie from the authorization file. - // - - updateCookie(); -} - -Auth::~Auth() -{ - delete [] display_; - delete [] file_; - - delete [] fakeCookie_; - delete [] realCookie_; - - delete [] fakeData_; - delete [] realData_; -} - -// -// At the present moment the cookie is read only once, -// at the time the instance is initialized. If the auth -// file changes along the life of the session, the old -// cookie will be used. This works with X servers beca- -// use of an undocumented "feature". See nx-X11. -// - -int Auth::updateCookie() -{ - if (isTimestamp(last_) == 0) - { - #ifdef TEST - *logofs << "Auth: Reading the X authorization file " - << "with last update at " << strMsTimestamp(last_) - << ".\n" << logofs_flush; - #endif - - if (getCookie() == 1 && validateCookie() == 1) - { - // - // It should rather be the modification time - // the auth file, so we can read it again if - // the file is changed. - // - - #ifdef TEST - *logofs << "Auth: Setting last X authorization file " - << "update at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - last_ = getTimestamp(); - - return 1; - } - - #ifdef PANIC - *logofs << "Auth: PANIC! Cannot read the cookie from the X " - << "authorization file.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot read the cookie from the X " - << "authorization file.\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Auth: WARNING! Skipping check on the X " - << "authorization file.\n" << logofs_flush; - #endif - - return 0; -} - -int Auth::getCookie() -{ - // - // Check the name of the auth file that we are going to use. - // It can be either the value of the XAUTHORITY environment - // or the default .Xauthority file in the user's home. - // - - char *environment; - - environment = getenv("XAUTHORITY"); - - if (environment != NULL && *environment != '\0') - { - strncpy(file_, environment, DEFAULT_STRING_LIMIT - 1); - } - else - { - snprintf(file_, DEFAULT_STRING_LIMIT - 1, "%s/.Xauthority", - control -> HomePath); - } - - *(file_ + DEFAULT_STRING_LIMIT - 1) = '\0'; - - #ifdef TEST - *logofs << "Auth: Using X authorization file '" << file_ - << "'.\n" << logofs_flush; - #endif - - // - // Use the nxauth command on Windows and the Mac, xauth - // on all the other platforms. On Windows we assume that - // the nxauth command is located under bin in the client - // installation directory. On Mac OS X we assume that the - // command is located directly in the client installation - // directory, to make bundle shipping easier. On all the - // other platforms we use the default xauth command that - // is in our path. - // - - char command[DEFAULT_STRING_LIMIT]; - - #if defined(__CYGWIN32__) - - snprintf(command, DEFAULT_STRING_LIMIT - 1, - "%s/bin/nxauth", control -> SystemPath); - - *(command + DEFAULT_STRING_LIMIT - 1) = '\0'; - - #elif defined(__APPLE__) - - snprintf(command, DEFAULT_STRING_LIMIT - 1, - "%s/nxauth", control -> SystemPath); - - *(command + DEFAULT_STRING_LIMIT - 1) = '\0'; - - #else - - strcpy(command, "xauth"); - - #endif - - #ifdef TEST - *logofs << "Auth: Using X auth command '" << command - << "'.\n" << logofs_flush; - #endif - - // - // The SSH code forces using the unix:n port when passing localhost:n. - // This is probably because localhost:n can fail to return a valid - // entry on machines where the hostname for localhost doesn't match - // exactly the 'localhost' string. For example, on a freshly installed - // Fedora Core 3 I get a 'localhost.localdomain/unix:0' entry. Query- - // ing 'xauth list localhost:0' results in an empty result, while the - // query 'xauth list unix:0' works as expected. Note anyway that if - // the cookie for the TCP connection on 'localhost' is set to a dif- - // ferent cookie than the one for the Unix connections, both SSH and - // NX will match the wrong cookie and session will fail. - // - - char line[DEFAULT_STRING_LIMIT]; - - if (strncmp(display_, "localhost:", 10) == 0) - { - snprintf(line, DEFAULT_STRING_LIMIT, "unix:%s", display_ + 10); - } - else - { - snprintf(line, DEFAULT_STRING_LIMIT, "%.200s", display_); - } - - const char *parameters[256]; - - parameters[0] = command; - parameters[1] = command; - parameters[2] = "-f"; - parameters[3] = file_; - parameters[4] = "list"; - parameters[5] = line; - parameters[6] = NULL; - - #ifdef TEST - *logofs << "Auth: Executing command "; - - for (int i = 0; i < 256 && parameters[i] != NULL; i++) - { - *logofs << "[" << parameters[i] << "]"; - } - - *logofs << ".\n" << logofs_flush; - #endif - - // - // Use the popen() function to read the result - // of the command. We would better use our own - // implementation. - // - - FILE *data = Popen((char *const *) parameters, "r"); - - int result = -1; - - if (data == NULL) - { - #ifdef PANIC - *logofs << "Auth: PANIC! Failed to execute the X auth command.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed to execute the X auth command.\n"; - - goto AuthGetCookieResult; - } - - if (fgets(line, DEFAULT_STRING_LIMIT, data) == NULL) - { - #ifdef WARNING - *logofs << "Auth: WARNING! Failed to read data from the X " - << "auth command.\n" << logofs_flush; - #endif - - #ifdef TEST - cerr << "Warning" << ": Failed to read data from the X " - << "auth command.\n"; - #endif - - #ifdef PANIC - *logofs << "Auth: WARNING! Generating a fake cookie for " - << "X authentication.\n" << logofs_flush; - #endif - - #ifdef TEST - cerr << "Warning" << ": Generating a fake cookie for " - << "X authentication.\n"; - #endif - - generateCookie(realCookie_); - } - else - { - #ifdef TEST - *logofs << "Auth: Checking cookie in string '" << line - << "'.\n" << logofs_flush; - #endif - - // - // Skip the hostname in the authority entry - // just in case it includes some white spaces. - // - - char *cookie = NULL; - - cookie = index(line, ':'); - - if (cookie == NULL) - { - cookie = line; - } - - if (sscanf(cookie, "%*s %*s %511s", realCookie_) != 1) - { - #ifdef PANIC - *logofs << "Auth: PANIC! Failed to identify the cookie " - << "in string '" << line << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed to identify the cookie " - << "in string '" << line << "'.\n"; - - goto AuthGetCookieResult; - } - - #ifdef TEST - *logofs << "Auth: Got cookie '" << realCookie_ - << "' from file '" << file_ << "'.\n" - << logofs_flush; - #endif - } - - result = 1; - -AuthGetCookieResult: - - if (data != NULL) - { - Pclose(data); - } - - return result; -} - -int Auth::validateCookie() -{ - unsigned int length = strlen(realCookie_); - - if (length > DEFAULT_STRING_LIMIT / 2 - 1 || - strlen(fakeCookie_) != length) - { - #ifdef PANIC - *logofs << "Auth: PANIC! Size mismatch between cookies '" - << realCookie_ << "' and '" << fakeCookie_ << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Size mismatch between cookies '" - << realCookie_ << "' and '" << fakeCookie_ << "'.\n"; - - goto AuthValidateCookieError; - } - - // - // The length of the resulting data will be - // half the size of the Hex cookie. - // - - length = length / 2; - - fakeData_ = new char[length]; - realData_ = new char[length]; - - if (fakeData_ == NULL || realData_ == NULL) - { - #ifdef PANIC - *logofs << "Auth: PANIC! Cannot allocate memory for the binary X " - << "authorization data.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot allocate memory for the binary X " - << "authorization data.\n"; - - goto AuthValidateCookieError; - } - - // - // Translate the real cookie from Hex data - // to its binary representation. - // - - unsigned int value; - - for (unsigned int i = 0; i < length; i++) - { - if (sscanf(realCookie_ + 2 * i, "%2x", &value) != 1) - { - #ifdef PANIC - *logofs << "Auth: PANIC! Bad X authorization data in real " - << "cookie '" << realCookie_ << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Bad X authorization data in real cookie '" - << realCookie_ << "'.\n"; - - goto AuthValidateCookieError; - } - - realData_[i] = value; - - if (sscanf(fakeCookie_ + 2 * i, "%2x", &value) != 1) - { - #ifdef PANIC - *logofs << "Auth: PANIC! Bad X authorization data in fake " - << "cookie '" << fakeCookie_ << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Bad X authorization data in fake cookie '" - << fakeCookie_ << "'.\n"; - - goto AuthValidateCookieError; - } - - fakeData_[i] = value; - } - - dataSize_ = length; - - #ifdef TEST - *logofs << "Auth: Validated real cookie '" - << realCookie_ << "' and fake cookie '" << fakeCookie_ - << "' with data with size " << dataSize_ << ".\n" - << logofs_flush; - - *logofs << "Auth: Ready to accept incoming connections.\n" - << logofs_flush; - #endif - - return 1; - -AuthValidateCookieError: - - delete [] fakeData_; - delete [] realData_; - - fakeData_ = NULL; - realData_ = NULL; - - dataSize_ = 0; - - return -1; -} - -int Auth::checkCookie(unsigned char *buffer) -{ - if (isValid() != 1) - { - #ifdef PANIC - *logofs << "Auth: PANIC! Attempt to check the X cookie with " - << "invalid authorization data.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Attempt to check the X cookie with " - << "invalid authorization data.\n"; - - return -1; - } - - const char *protoName = "MIT-MAGIC-COOKIE-1"; - int protoSize = strlen(protoName); - - int matchedProtoSize; - int matchedDataSize; - - if (buffer[0] == 0x42) - { - // - // Byte order is MSB first. - // - - matchedProtoSize = 256 * buffer[6] + buffer[7]; - matchedDataSize = 256 * buffer[8] + buffer[9]; - } - else if (buffer[0] == 0x6c) - { - // - // Byte order is LSB first. - // - - matchedProtoSize = buffer[6] + 256 * buffer[7]; - matchedDataSize = buffer[8] + 256 * buffer[9]; - } - else - { - #ifdef WARNING - *logofs << "Auth: WARNING! Bad X connection data in the buffer.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Bad X connection data in the buffer.\n"; - - return -1; - } - - // - // Check if both the authentication protocol - // and the fake cookie match our data. - // - - int protoOffset = 12; - - #ifdef TEST - *logofs << "Auth: Received a protocol size of " - << matchedProtoSize << " bytes.\n" - << logofs_flush; - #endif - - if (matchedProtoSize != protoSize || - memcmp(buffer + protoOffset, protoName, protoSize) != 0) - { - #ifdef WARNING - *logofs << "Auth: WARNING! Protocol mismatch or no X " - << "authentication data.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Protocol mismatch or no X " - << "authentication data.\n"; - - return -1; - } - - int dataOffset = protoOffset + ((matchedProtoSize + 3) & ~3); - - #ifdef TEST - *logofs << "Auth: Received a data size of " - << matchedDataSize << " bytes.\n" - << logofs_flush; - #endif - - if (matchedDataSize != dataSize_ || - memcmp(buffer + dataOffset, fakeData_, dataSize_) != 0) - { - #ifdef WARNING - *logofs << "Auth: WARNING! Cookie mismatch in the X " - << "authentication data.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Cookie mismatch in the X " - << "authentication data.\n"; - - return -1; - } - - // - // Everything is OK. Replace the fake data. - // - - #ifdef TEST - *logofs << "Auth: Replacing fake X authentication data " - << "with the real data.\n" << logofs_flush; - #endif - - memcpy(buffer + dataOffset, realData_, dataSize_); - - return 1; -} - -void Auth::generateCookie(char *cookie) -{ - // - // Code is from the SSH implementation, except that - // we use a much weaker random number generator. - // This is not critical, anyway, as this is just a - // fake cookie. The X server doesn't have a cookie - // for the display, so it will ignore the value we - // feed to it. - // - - T_timestamp timer = getTimestamp(); - - srand((unsigned int) timer.tv_usec); - - unsigned int data = rand(); - - for (int i = 0; i < 16; i++) - { - if (i % 4 == 0) - { - data = rand(); - } - - snprintf(cookie + 2 * i, 3, "%02x", data & 0xff); - - data >>= 8; - } - - generatedCookie_ = 1; - - #ifdef TEST - *logofs << "Auth: Generated X cookie string '" - << cookie << "'.\n" << logofs_flush; - #endif -} diff --git a/nxcomp/Auth.h b/nxcomp/Auth.h deleted file mode 100644 index d51d9a26f..000000000 --- a/nxcomp/Auth.h +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Auth_H -#define Auth_H - -#include "Timestamp.h" - -// -// Handle the forwarding of authorization credentials -// to the X server by replacing the fake cookie with -// the real cookie as it is read from the auth file. -// At the moment only the MIT-MAGIC-COOKIE-1 cookies -// are recognized. The implementation is based on the -// corresponding code found in the SSH client. -// - -class Auth -{ - public: - - // - // Must be created by passing the fake cookie that - // will be forwarded by the remote end and with the - // real X display that is going to be used for the - // session. - // - - Auth(char *display, char *cookie); - - ~Auth(); - - int isValid() - { - return (isTimestamp(last_) == 1 && fakeCookie_ != NULL && - *fakeCookie_ != '\0' && realCookie_ != NULL && - *realCookie_ != '\0' && fakeData_ != NULL && - realData_ != NULL && dataSize_ != 0); - } - - int isFake() const - { - return generatedCookie_; - } - - // - // Method called in the channel class to find if the - // provided cookie matches the fake one. If the data - // matches, the fake cookie is replaced with the real - // one. - // - - int checkCookie(unsigned char *buffer); - - protected: - - // - // Update the real cookie for the display. If called - // a further time, check if the auth file is changed - // and get the new cookie. - // - - int updateCookie(); - - // - // Find out which authorization file is to be used - // and query the cookie for the current display. - // - - int getCookie(); - - // - // Extract the binary data from the cookies so that - // data can be directly compared at the time it is - // taken from the X request. - // - - int validateCookie(); - - // - // Generate a fake random cookie and copy it to the - // provided string. - // - - void generateCookie(char *cookie); - - private: - - char *display_; - char *file_; - - T_timestamp last_; - - char *fakeCookie_; - char *realCookie_; - - char *fakeData_; - char *realData_; - - int dataSize_; - - int generatedCookie_; -}; - -#endif /* Auth_H */ diff --git a/nxcomp/Bitmap.cpp b/nxcomp/Bitmap.cpp deleted file mode 100644 index fbc34a55e..000000000 --- a/nxcomp/Bitmap.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "Bitmap.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -int UnpackBitmap(T_geometry *geometry, unsigned char method, unsigned char *src_data, - int src_size, int dst_bpp, int dst_width, int dst_height, - unsigned char *dst_data, int dst_size) -{ - if (dst_bpp != 32) - { - #ifdef TEST - *logofs << "UnpackBitmap: Nothing to do with " - << "image of " << dst_bpp << " bits per plane " - << "and size " << src_size << ".\n" - << logofs_flush; - #endif - - if (src_size != dst_size) - { - #ifdef PANIC - *logofs << "UnpackBitmap: PANIC! Size mismatch with " - << src_size << " bytes in the source and " - << dst_size << " in the destination.\n" - << logofs_flush; - #endif - - return -1; - } - - memcpy(dst_data, src_data, src_size); - - return 1; - } - else if (src_size != dst_width * dst_height * 3 || - dst_size != dst_width * dst_height * 4) - { - #ifdef PANIC - *logofs << "UnpackBitmap: PANIC! Size mismatch with " - << src_size << " bytes in the source and " - << dst_size << " in the destination.\n" - << logofs_flush; - #endif - - return -1; - } - - /* - * Insert the 4th byte in the bitmap. - */ - - unsigned char *next_src = src_data; - unsigned char *next_dst = dst_data; - - if (geometry -> image_byte_order == LSBFirst) - { - while (next_src < src_data + src_size) - { - *next_dst++ = *next_src++; - *next_dst++ = *next_src++; - *next_dst++ = *next_src++; - - next_dst++; - } - } - else - { - while (next_src < src_data + src_size) - { - next_dst++; - - *next_dst++ = *next_src++; - *next_dst++ = *next_src++; - *next_dst++ = *next_src++; - } - } - - #ifdef TEST - *logofs << "UnpackBitmap: Unpacked " << src_size - << " bytes to a buffer of " << dst_size - << " with " << dst_bpp << " bits per plane.\n" - << logofs_flush; - #endif - - return 1; -} diff --git a/nxcomp/Bitmap.h b/nxcomp/Bitmap.h deleted file mode 100644 index 8143e3125..000000000 --- a/nxcomp/Bitmap.h +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Bitmap_H -#define Bitmap_H - -#include "Unpack.h" - -int UnpackBitmap(T_geometry *geometry, unsigned char method, - unsigned char *src_data, int src_size, int dst_bpp, - int dst_width, int dst_height, unsigned char *dst_data, - int dst_size); - -#endif /* Bitmap_H */ diff --git a/nxcomp/BlockCache.cpp b/nxcomp/BlockCache.cpp deleted file mode 100644 index 76f7fd797..000000000 --- a/nxcomp/BlockCache.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include "BlockCache.h" - - -int BlockCache::compare(unsigned int size, const unsigned char *data, - int overwrite) -{ - int match = 0; - if (size == size_) - { - match = 1; - for (unsigned int i = 0; i < size_; i++) - if (data[i] != buffer_[i]) - { - match = 0; - break; - } - } - if (!match && overwrite) - set(size, data); - return match; -} - - -void BlockCache::set(unsigned int size, const unsigned char *data) -{ - if (size_ < size) - { - delete[]buffer_; - buffer_ = new unsigned char[size]; - } - size_ = size; - memcpy(buffer_, data, size); - checksum_ = checksum(size, data); -} - - -unsigned int BlockCache::checksum(unsigned int size, const unsigned char *data) -{ - unsigned int sum = 0; - unsigned int shift = 0; - const unsigned char *next = data; - for (unsigned int i = 0; i < size; i++) - { - unsigned int value = (unsigned int) *next++; - sum += (value << shift); - shift++; - if (shift == 8) - shift = 0; - } - return sum; -} diff --git a/nxcomp/BlockCache.h b/nxcomp/BlockCache.h deleted file mode 100644 index 48e586966..000000000 --- a/nxcomp/BlockCache.h +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef BlockCache_H -#define BlockCache_H - - -// Cache to hold an arbitrary-length block of bytes - -class BlockCache -{ - public: - BlockCache():buffer_(0), size_(0), checksum_(0) - { - } - ~BlockCache() - { - delete[]buffer_; - } - int compare(unsigned int size, const unsigned char *data, - int overwrite = 1); - void set(unsigned int size, const unsigned char *data); - - unsigned int getLength() const - { - return size_; - } - unsigned int getChecksum() const - { - return checksum_; - } - const unsigned char *getData() const - { - return buffer_; - } - - static unsigned int checksum(unsigned int size, const unsigned char *data); - -private: - unsigned char *buffer_; - unsigned int size_; - unsigned int checksum_; -}; - -#endif /* BlockCache_H */ diff --git a/nxcomp/BlockCacheSet.cpp b/nxcomp/BlockCacheSet.cpp deleted file mode 100644 index 3fd5e1ac7..000000000 --- a/nxcomp/BlockCacheSet.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "BlockCacheSet.h" - - -BlockCacheSet::BlockCacheSet(unsigned int numCaches): - caches_(new BlockCache *[numCaches]), size_(numCaches), - length_(0) -{ - for (unsigned int i = 0; i < numCaches; i++) - caches_[i] = new BlockCache(); -} - - -BlockCacheSet::~BlockCacheSet() -{ - // - // TODO: There is still a strange segfault occurring - // at random time under Cygwin, when proxy is being - // shutdown. Problem appeared just after upgrading - // to the latest version of the Cygwin DLL. A stack - // trace, obtained at the last minute, reveals that - // failure happens in this destructor. - // - - #ifndef __CYGWIN32__ - - for (unsigned int i = 0; i < size_; i++) - delete caches_[i]; - delete[]caches_; - - #endif /* ifdef __CYGWIN32__ */ -} - - -int -BlockCacheSet::lookup(unsigned int dataLength, const unsigned char *data, - unsigned int &index) -{ - unsigned int checksum = BlockCache::checksum(dataLength, data); - for (unsigned int i = 0; i < length_; i++) - if ((caches_[i]->getChecksum() == checksum) && - (caches_[i]->compare(dataLength, data, 0))) - { - // match - index = i; - if (i) - { - BlockCache *save = caches_[i]; - unsigned int target = (i >> 1); - do - { - caches_[i] = caches_[i - 1]; - i--; - } - while (i > target); - caches_[target] = save; - } - return 1; - } - // no match - unsigned int insertionPoint = (length_ >> 1); - unsigned int start; - if (length_ >= size_) - start = size_ - 1; - else - { - start = length_; - length_++; - } - BlockCache *save = caches_[start]; - for (unsigned int k = start; k > insertionPoint; k--) - caches_[k] = caches_[k - 1]; - caches_[insertionPoint] = save; - save->set(dataLength, data); - return 0; -} - - -void -BlockCacheSet::get(unsigned index, unsigned int &size, - const unsigned char *&data) -{ - size = caches_[index]->getLength(); - data = caches_[index]->getData(); - if (index) - { - BlockCache *save = caches_[index]; - unsigned int target = (index >> 1); - do - { - caches_[index] = caches_[index - 1]; - index--; - } - while (index > target); - caches_[target] = save; - } -} - - - -void -BlockCacheSet::set(unsigned int dataLength, const unsigned char *data) -{ - unsigned int insertionPoint = (length_ >> 1); - unsigned int start; - if (length_ >= size_) - start = size_ - 1; - else - { - start = length_; - length_++; - } - BlockCache *save = caches_[start]; - for (unsigned int k = start; k > insertionPoint; k--) - caches_[k] = caches_[k - 1]; - caches_[insertionPoint] = save; - save->set(dataLength, data); -} diff --git a/nxcomp/BlockCacheSet.h b/nxcomp/BlockCacheSet.h deleted file mode 100644 index 97273b0e0..000000000 --- a/nxcomp/BlockCacheSet.h +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef BlockCacheSet_H -#define BlockCacheSet_H - -#include "BlockCache.h" - - -class BlockCacheSet -{ - public: - BlockCacheSet(unsigned int numCaches); - ~BlockCacheSet(); - - int lookup(unsigned int size, const unsigned char *data, - unsigned int &index); - void get(unsigned int index, unsigned int &size, const unsigned char *&data); - void set(unsigned int size, const unsigned char *data); - - private: - BlockCache ** caches_; - unsigned int size_; - unsigned int length_; -}; - -#endif /* BlockCacheSet_H */ diff --git a/nxcomp/ChangeGC.cpp b/nxcomp/ChangeGC.cpp deleted file mode 100644 index f06984a10..000000000 --- a/nxcomp/ChangeGC.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ChangeGC.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int ChangeGCStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ChangeGCMessage *changeGC = (ChangeGCMessage *) message; - - // - // Here is the fingerprint. - // - - changeGC -> gcontext = GetULONG(buffer + 4, bigEndian); - changeGC -> value_mask = GetULONG(buffer + 8, bigEndian); - - // - // Clear the unused bytes carried in the - // payload to increase the effectiveness - // of the caching algorithm. - // - - if ((int) size > dataOffset) - { - #ifdef DEBUG - *logofs << name() << ": Removing unused bytes from the " - << "data payload.\n" << logofs_flush; - #endif - - changeGC -> value_mask &= (1 << 23) - 1; - - unsigned int mask = 0x1; - unsigned char *source = (unsigned char *) buffer + CHANGEGC_DATA_OFFSET; - unsigned long value = 0; - - for (unsigned int i = 0; i < 23; i++) - { - if (changeGC -> value_mask & mask) - { - value = GetULONG(source, bigEndian); - - value &= (0xffffffff >> (32 - CREATEGC_FIELD_WIDTH[i])); - - PutULONG(value, source, bigEndian); - - source += 4; - } - - mask <<= 1; - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int ChangeGCStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ChangeGCMessage *changeGC = (ChangeGCMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(changeGC -> gcontext, buffer + 4, bigEndian); - PutULONG(changeGC -> value_mask, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void ChangeGCStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - ChangeGCMessage *changeGC = (ChangeGCMessage *) message; - - *logofs << name() << ": Identity gcontext " << changeGC -> gcontext - << ", mask " << changeGC -> value_mask << ", size " - << changeGC -> size_ << ".\n" << logofs_flush; - #endif -} - -void ChangeGCStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -/* - md5_append(md5_state_, buffer + 4, 8); -*/ - md5_append(md5_state_, buffer + 8, 4); -} - -void ChangeGCStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - ChangeGCMessage *changeGC = (ChangeGCMessage *) message; - ChangeGCMessage *cachedChangeGC = (ChangeGCMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << changeGC -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(changeGC -> gcontext, clientCache -> gcCache); - - cachedChangeGC -> gcontext = changeGC -> gcontext; -} - -void ChangeGCStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - ChangeGCMessage *changeGC = (ChangeGCMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - changeGC -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << changeGC -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} diff --git a/nxcomp/ChangeGC.h b/nxcomp/ChangeGC.h deleted file mode 100644 index 9cac90e66..000000000 --- a/nxcomp/ChangeGC.h +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ChangeGC_H -#define ChangeGC_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define CHANGEGC_ENABLE_CACHE 1 -#define CHANGEGC_ENABLE_DATA 0 -#define CHANGEGC_ENABLE_SPLIT 0 -#define CHANGEGC_ENABLE_COMPRESS 0 - -#define CHANGEGC_DATA_LIMIT 144 -#define CHANGEGC_DATA_OFFSET 12 - -#define CHANGEGC_CACHE_SLOTS 3000 -#define CHANGEGC_CACHE_THRESHOLD 3 -#define CHANGEGC_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class ChangeGCMessage : public Message -{ - friend class ChangeGCStore; - - public: - - ChangeGCMessage() - { - } - - ~ChangeGCMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int gcontext; - unsigned int value_mask; -}; - -class ChangeGCStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - ChangeGCStore() : MessageStore() - { - enableCache = CHANGEGC_ENABLE_CACHE; - enableData = CHANGEGC_ENABLE_DATA; - enableSplit = CHANGEGC_ENABLE_SPLIT; - enableCompress = CHANGEGC_ENABLE_COMPRESS; - - dataLimit = CHANGEGC_DATA_LIMIT; - dataOffset = CHANGEGC_DATA_OFFSET; - - cacheSlots = CHANGEGC_CACHE_SLOTS; - cacheThreshold = CHANGEGC_CACHE_THRESHOLD; - cacheLowerThreshold = CHANGEGC_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~ChangeGCStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "ChangeGC"; - } - - virtual unsigned char opcode() const - { - return X_ChangeGC; - } - - virtual unsigned int storage() const - { - return sizeof(ChangeGCMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new ChangeGCMessage(); - } - - virtual Message *create(const Message &message) const - { - return new ChangeGCMessage((const ChangeGCMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (ChangeGCMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; -}; - -#endif /* ChangeGC_H */ diff --git a/nxcomp/ChangeProperty.cpp b/nxcomp/ChangeProperty.cpp deleted file mode 100644 index dbfb8f5d7..000000000 --- a/nxcomp/ChangeProperty.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ChangeProperty.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int ChangePropertyStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; - - changeProperty -> mode = *(buffer + 1); - changeProperty -> format = *(buffer + 16); - - changeProperty -> window = GetULONG(buffer + 4, bigEndian); - changeProperty -> property = GetULONG(buffer + 8, bigEndian); - changeProperty -> type = GetULONG(buffer + 12, bigEndian); - changeProperty -> length = GetULONG(buffer + 20, bigEndian); - - // - // Cleanup the padding bytes. - // - - unsigned int uiFormat; - unsigned int uiLengthInBytes; - - if ((int) size > CHANGEPROPERTY_DATA_OFFSET) - { - uiFormat = *(buffer + 16); - - uiLengthInBytes = changeProperty -> length; - - #ifdef DEBUG - *logofs << name() << ": length " << uiLengthInBytes - << ", format " << uiFormat << ", size " - << size << ".\n" << logofs_flush; - #endif - - if (uiFormat == 16) - { - uiLengthInBytes <<= 1; - } - else if (uiFormat == 32) - { - uiLengthInBytes <<= 2; - } - - unsigned char *end = ((unsigned char *) buffer) + size; - unsigned char *pad = ((unsigned char *) buffer) + CHANGEPROPERTY_DATA_OFFSET + uiLengthInBytes; - - CleanData((unsigned char *) pad, end - pad); - } - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int ChangePropertyStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; - - *(buffer + 1) = changeProperty -> mode; - *(buffer + 16) = changeProperty -> format; - - PutULONG(changeProperty -> window, buffer + 4, bigEndian); - PutULONG(changeProperty -> property, buffer + 8, bigEndian); - PutULONG(changeProperty -> type, buffer + 12, bigEndian); - PutULONG(changeProperty -> length, buffer + 20, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void ChangePropertyStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; - - *logofs << name() << ": Identity mode " << (unsigned int) changeProperty -> mode << ", format " - << (unsigned int) changeProperty -> format << ", window " << changeProperty -> window - << ", property " << changeProperty -> property << ", type " << changeProperty -> type - << ", length " << changeProperty -> length << ", size " << changeProperty -> size_ - << ".\n" << logofs_flush; - - #endif -} - -void ChangePropertyStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 1, 1); - md5_append(md5_state_, buffer + 16, 1); - - md5_append(md5_state_, buffer + 8, 4); - md5_append(md5_state_, buffer + 12, 4); - md5_append(md5_state_, buffer + 20, 4); -} - -void ChangePropertyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; - ChangePropertyMessage *cachedChangeProperty = (ChangePropertyMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << changeProperty -> window - << " as window field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(changeProperty -> window, clientCache -> windowCache); - - cachedChangeProperty -> window = changeProperty -> window; -} - -void ChangePropertyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> windowCache); - - changeProperty -> window = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << changeProperty -> window - << " as window field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/ChangeProperty.h b/nxcomp/ChangeProperty.h deleted file mode 100644 index c06ce10fc..000000000 --- a/nxcomp/ChangeProperty.h +++ /dev/null @@ -1,189 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ChangeProperty_H -#define ChangeProperty_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define CHANGEPROPERTY_ENABLE_CACHE 1 -#define CHANGEPROPERTY_ENABLE_DATA 0 -#define CHANGEPROPERTY_ENABLE_SPLIT 0 -#define CHANGEPROPERTY_ENABLE_COMPRESS 0 - -#define CHANGEPROPERTY_DATA_LIMIT 28688 -#define CHANGEPROPERTY_DATA_OFFSET 24 - -#define CHANGEPROPERTY_CACHE_SLOTS 2000 -#define CHANGEPROPERTY_CACHE_THRESHOLD 2 -#define CHANGEPROPERTY_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class ChangePropertyMessage : public Message -{ - friend class ChangePropertyStore; - - public: - - ChangePropertyMessage() - { - } - - ~ChangePropertyMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char mode; - unsigned char format; - unsigned int window; - unsigned int property; - unsigned int type; - unsigned int length; -}; - -class ChangePropertyStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - ChangePropertyStore() : MessageStore() - { - enableCache = CHANGEPROPERTY_ENABLE_CACHE; - enableData = CHANGEPROPERTY_ENABLE_DATA; - enableSplit = CHANGEPROPERTY_ENABLE_SPLIT; - enableCompress = CHANGEPROPERTY_ENABLE_COMPRESS; - - dataLimit = CHANGEPROPERTY_DATA_LIMIT; - dataOffset = CHANGEPROPERTY_DATA_OFFSET; - - cacheSlots = CHANGEPROPERTY_CACHE_SLOTS; - cacheThreshold = CHANGEPROPERTY_CACHE_THRESHOLD; - cacheLowerThreshold = CHANGEPROPERTY_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~ChangePropertyStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "ChangeProperty"; - } - - virtual unsigned char opcode() const - { - return X_ChangeProperty; - } - - virtual unsigned int storage() const - { - return sizeof(ChangePropertyMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new ChangePropertyMessage(); - } - - virtual Message *create(const Message &message) const - { - return new ChangePropertyMessage((const ChangePropertyMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (ChangePropertyMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* ChangeProperty_H */ diff --git a/nxcomp/Channel.cpp b/nxcomp/Channel.cpp deleted file mode 100644 index 41a09e951..000000000 --- a/nxcomp/Channel.cpp +++ /dev/null @@ -1,2035 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Channel.h" - -#include "List.h" -#include "Proxy.h" -#include "Statistics.h" - -#include "StaticCompressor.h" - -#include "NXalert.h" - -extern Proxy *proxy; - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Log the operations related to splits. -// - -#undef SPLIT - -#undef COUNT - -#define COUNT_MAJOR_OPCODE 154 - -#undef MONITOR - -#define MONITOR_MAJOR_OPCODE 154 -#define MONITOR_MINOR_OPCODE 23 - -#undef CLEAR - -#define CLEAR_MAJOR_OPCODE 154 -#define CLEAR_MINOR_OPCODE 23 - -// -// Define this to know how many messages -// are allocated and deallocated. -// - -#undef REFERENCES - -// -// Set to the descriptor of the first X -// channel successfully connected. -// - -int Channel::firstClient_ = -1; - -// -// Port used for font server connections. -// - -int Channel::fontPort_ = -1; - -// -// This is used for reference count. -// - -#ifdef REFERENCES - -int Channel::references_ = 0; - -#endif - -Channel::Channel(Transport *transport, StaticCompressor *compressor) - - : transport_(transport), compressor_(compressor) -{ - fd_ = transport_ -> fd(); - - finish_ = 0; - closing_ = 0; - drop_ = 0; - congestion_ = 0; - priority_ = 0; - - alert_ = 0; - - firstRequest_ = 1; - firstReply_ = 1; - - enableCache_ = 1; - enableSplit_ = 1; - enableSave_ = 1; - enableLoad_ = 1; - - // - // Must be set by proxy. - // - - opcodeStore_ = NULL; - - clientStore_ = NULL; - serverStore_ = NULL; - - clientCache_ = NULL; - serverCache_ = NULL; - - #ifdef REFERENCES - *logofs << "Channel: Created new Channel at " - << this << " out of " << ++references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -Channel::~Channel() -{ - if (firstClient_ == fd_) - { - firstClient_ = -1; - } - - #ifdef REFERENCES - *logofs << "Channel: Deleted Channel at " - << this << " out of " << --references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -int Channel::handleEncode(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, - MessageStore *store, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - #ifdef MONITOR - - static float totalMessages = 0; - static float totalBits = 0; - - int bits; - int diff; - - bits = encodeBuffer.getBits(); - - #endif - - // - // Check if message can be differentially - // encoded using a similar message in the - // message store. - // - - #ifdef COUNT - - if (*(buffer) == COUNT_MAJOR_OPCODE) - { - if (*(buffer) < 128) - { - *logofs << "handleEncode: Handling OPCODE#" << (unsigned int) *(buffer) - << ".\n" << logofs_flush; - } - else - { - *logofs << "handleEncode: Handling OPCODE#" << (unsigned int) *(buffer) - << " MINOR#" << (unsigned int) *(buffer + 1) << ".\n" - << logofs_flush; - } - } - - #endif - - #ifdef CLEAR - - if (*(buffer) == CLEAR_MAJOR_OPCODE && - (CLEAR_MINOR_OPCODE == -1 || *(buffer + 1) == CLEAR_MINOR_OPCODE)) - { - *((unsigned char *) buffer) = X_NoOperation; - - *((unsigned char *) buffer + 1) = '\0'; - - CleanData((unsigned char *) buffer + 4, size - 4); - } - - #endif - - if (handleEncodeCached(encodeBuffer, channelCache, - store, buffer, size) == 1) - { - #ifdef MONITOR - - diff = encodeBuffer.getBits() - bits; - - if (*(buffer) == MONITOR_MAJOR_OPCODE && - (MONITOR_MINOR_OPCODE == -1 || *(buffer + 1) == MONITOR_MINOR_OPCODE)) - { - totalMessages++; - - totalBits += diff; - - *logofs << "handleEncode: Handled cached OPCODE#" << (unsigned int) *(buffer) - << " MINOR#" << (unsigned int) *(buffer + 1) << ". " << size - << " bytes in, " << diff << " bits (" << ((float) diff) / 8 - << " bytes) out. Average " << totalBits / totalMessages - << "/1.\n" << logofs_flush; - } - - #endif - - // - // Let the channel update the split store - // and notify the agent in the case of a - // cache hit. - // - - if (store -> enableSplit) - { - handleSplit(encodeBuffer, store, store -> lastAction, - store -> lastHit, opcode, buffer, size); - } - - return 1; - } - - // - // A similar message could not be found in - // cache or message must be discarded. Must - // transmit the message using the field by - // field differential encoding. - // - - handleEncodeIdentity(encodeBuffer, channelCache, - store, buffer, size, bigEndian_); - - // - // Check if message has a distinct data part. - // - - if (store -> enableData) - { - // - // If message split was requested by agent then send data - // out-of-band, dividing it in small chunks. Until message - // is completely transferred, keep in the split store a - // dummy version of the message, with data replaced with a - // pattern. - // - // While data is being transferred, agent should have put - // the resource (for example its client) asleep. It can - // happen, though, that a different client would reference - // the same message. We cannot issue a cache hit for images - // being split (such images are put in store in 'incomplete' - // state), so we need to handle this case. - // - - if (store -> enableSplit == 1) - { - // - // Let the channel decide what to do with the - // message. If the split can't take place be- - // cause the split store is full, the channel - // will tell the remote side that the data is - // going to follow. - // - - if (handleSplit(encodeBuffer, store, store -> lastAction, - (store -> lastAction == IS_ADDED ? store -> lastAdded : 0), - opcode, buffer, size) == 1) - { - #ifdef MONITOR - - diff = encodeBuffer.getBits() - bits; - - if (*(buffer) == MONITOR_MAJOR_OPCODE && - (MONITOR_MINOR_OPCODE == -1 || *(buffer + 1) == MONITOR_MINOR_OPCODE)) - { - totalMessages++; - - totalBits += diff; - - *logofs << "handleEncode: Handled split OPCODE#" << (unsigned int) *(buffer) - << " MINOR#" << (unsigned int) *(buffer + 1) << ". " << size - << " bytes in, " << diff << " bits (" << ((float) diff) / 8 - << " bytes) out. Average " << totalBits / totalMessages - << "/1.\n" << logofs_flush; - } - - #endif - - return 0; - } - } - - // - // The split did not take place and we are going - // to transfer the data part. Check if the static - // compression of the data section is enabled. - // This is the case of all messages not having a - // special differential encoding or messages that - // we want to store in cache in compressed form. - // - - unsigned int offset = store -> identitySize(buffer, size); - - if (store -> enableCompress) - { - unsigned char *data = NULL; - unsigned int dataSize = 0; - - int compressed = handleCompress(encodeBuffer, opcode, offset, - buffer, size, data, dataSize); - if (compressed < 0) - { - return -1; - } - else if (compressed > 0) - { - // - // Update the size of the message according - // to the result of the data compression. - // - - handleUpdate(store, size - offset, dataSize); - } - } - else - { - handleCopy(encodeBuffer, opcode, offset, buffer, size); - } - } - - #ifdef MONITOR - - diff = encodeBuffer.getBits() - bits; - - if (*(buffer) == MONITOR_MAJOR_OPCODE && - (MONITOR_MINOR_OPCODE == -1 || *(buffer + 1) == MONITOR_MINOR_OPCODE)) - { - totalMessages++; - - totalBits += diff; - - *logofs << "handleEncode: Handled OPCODE#" << (unsigned int) *(buffer) - << " MINOR#" << (unsigned int) *(buffer + 1) << ". " << size - << " bytes in, " << diff << " bits (" << ((float) diff) / 8 - << " bytes) out. Average " << totalBits / totalMessages - << "/1.\n" << logofs_flush; - } - - #endif - - return 0; -} - -int Channel::handleDecode(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, - MessageStore *store, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - // - // Check first if the message is in the - // message store. - // - - unsigned int split = 0; - - if (handleDecodeCached(decodeBuffer, channelCache, - store, buffer, size) == 1) - { - // - // Let the channel update the split store - // in the case of a message being cached. - // - - if (store -> enableSplit == 1) - { - // Since ProtoStep7 (#issue 108) - #ifdef DEBUG - *logofs << "handleDecode: " << store -> name() - << ": Checking if the message was split.\n" - << logofs_flush; - #endif - - decodeBuffer.decodeBoolValue(split); - - if (split == 1) - { - handleSplit(decodeBuffer, store, store -> lastAction, - store -> lastHit, opcode, buffer, size); - - handleCleanAndNullRequest(opcode, buffer, size); - } - } - - return 1; - } - - // - // Decode the full identity. - // - - handleDecodeIdentity(decodeBuffer, channelCache, store, buffer, - size, bigEndian_, &writeBuffer_); - - // - // Check if the message has a distinct - // data part. - // - - if (store -> enableData) - { - // - // Check if message has been split. - // - - if (store -> enableSplit) - { - #ifdef DEBUG - *logofs << "handleDecode: " << store -> name() - << ": Checking if the message was split.\n" - << logofs_flush; - #endif - - decodeBuffer.decodeBoolValue(split); - - if (split == 1) - { - // - // If the message was added to the store, - // create the entry without the data part. - // - - handleSaveSplit(store, buffer, size); - - handleSplit(decodeBuffer, store, store -> lastAction, - (store -> lastAction == IS_ADDED ? store -> lastAdded : 0), - opcode, buffer, size); - - handleCleanAndNullRequest(opcode, buffer, size); - - return 0; - } - } - - // - // Decode the data part. - // - - unsigned int offset = store -> identitySize(buffer, size); - - if (store -> enableCompress) - { - const unsigned char *data = NULL; - unsigned int dataSize = 0; - - int decompressed = handleDecompress(decodeBuffer, opcode, offset, - buffer, size, data, dataSize); - if (decompressed < 0) - { - return -1; - } - else if (decompressed > 0) - { - // - // The message has been transferred - // in compressed format. - // - - handleSave(store, buffer, size, data, dataSize); - - if (store -> enableSplit) - { - if (split == 1) - { - handleSplit(decodeBuffer, store, store -> lastAction, - (store -> lastAction == IS_ADDED ? store -> lastAdded : 0), - opcode, buffer, size); - - handleCleanAndNullRequest(opcode, buffer, size); - } - } - - return 0; - } - } - else - { - // - // Static compression of the data part - // was not enabled for this message. - // - - handleCopy(decodeBuffer, opcode, offset, buffer, size); - } - } - - // - // The message doesn't have a data part - // or the data was not compressed. - // - - handleSave(store, buffer, size); - - if (store -> enableSplit) - { - if (split == 1) - { - handleSplit(decodeBuffer, store, store -> lastAction, - (store -> lastAction == IS_ADDED ? store -> lastAdded : 0), - opcode, buffer, size); - - handleCleanAndNullRequest(opcode, buffer, size); - } - } - - return 0; -} - -int Channel::handleEncodeCached(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, - MessageStore *store, const unsigned char *buffer, - const unsigned int size) -{ - if (control -> LocalDeltaCompression == 0 || - enableCache_ == 0 || store -> enableCache == 0) - { - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeActionValue(is_discarded, - store -> lastActionCache); - - store -> lastAction = is_discarded; - - return 0; - } - - #ifdef DEBUG - *logofs << "handleEncodeCached: " << store -> name() - << ": Going to handle a new message of this class.\n" - << logofs_flush; - #endif - - // - // Check if the estimated size of cache is greater - // than the requested limit. If it is the case make - // some room by deleting one or more messages. - // - - int position; - - while (mustCleanStore(store) == 1 && canCleanStore(store) == 1) - { - #ifdef DEBUG - *logofs << "handleEncodeCached: " << store -> name() - << ": Trying to reduce size of message store.\n" - << logofs_flush; - #endif - - position = store -> clean(use_checksum); - - if (position == nothing) - { - #ifdef TEST - *logofs << "handleEncodeCached: " << store -> name() - << ": WARNING! No message found to be " - << "actually removed.\n" << logofs_flush; - #endif - - break; - } - - #ifdef DEBUG - *logofs << "handleEncodeCached: " << store -> name() - << ": Message at position " << position - << " will be removed.\n" << logofs_flush; - #endif - - // - // Encode the position of message to - // be discarded. - // - - store -> lastRemoved = position; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeActionValue(is_removed, store -> lastRemoved, - store -> lastActionCache); - - #ifdef DEBUG - *logofs << "handleEncodeCached: " << store -> name() << ": Going to " - << "clean up message at position " << position << ".\n" - << logofs_flush; - #endif - - store -> remove(position, use_checksum, discard_data); - - #ifdef DEBUG - *logofs << "handleEncodeCached: " << store -> name() << ": There are " - << store -> getSize() << " messages in the store out of " - << store -> cacheSlots << " slots.\n" << logofs_flush; - - *logofs << "handleEncodeCached: " << store -> name() - << ": Size of store is " << store -> getLocalStorageSize() - << " bytes locally and " << store -> getRemoteStorageSize() - << " bytes remotely.\n" << logofs_flush; - - *logofs << "handleEncodeCached: " << store -> name() - << ": Size of total cache is " << store -> getLocalTotalStorageSize() - << " bytes locally and " << store -> getRemoteTotalStorageSize() - << " bytes remotely.\n" << logofs_flush; - #endif - } - - #ifdef DEBUG - - if (mustCleanStore(store) == 1 && canCleanStore(store) == 0) - { - *logofs << "handleEncodeCached: " << store -> name() - << ": Store would need a clean but operation will be delayed.\n" - << logofs_flush; - - *logofs << "handleEncodeCached: " << store -> name() << ": There are " - << store -> getSize() << " messages in the store out of " - << store -> cacheSlots << " slots.\n" << logofs_flush; - - *logofs << "handleEncodeCached: " << store -> name() - << ": Size of store is " << store -> getLocalStorageSize() - << " bytes locally and " << store -> getRemoteStorageSize() - << " bytes remotely.\n" << logofs_flush; - - *logofs << "handleEncodeCached: " << store -> name() - << ": Size of total cache is " << store -> getLocalTotalStorageSize() - << " bytes locally and " << store -> getRemoteTotalStorageSize() - << " bytes remotely.\n" << logofs_flush; - } - - #endif - - // - // If 'on the wire' size of message exceeds the - // allowed limit then avoid to store it in the - // cache. - // - - if (store -> validateMessage(buffer, size) == 0) - { - #ifdef TEST - *logofs << "handleEncodeCached: " << store -> name() - << ": Message with size " << size << " ignored.\n" - << logofs_flush; - #endif - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeActionValue(is_discarded, - store -> lastActionCache); - - store -> lastAction = is_discarded; - - return 0; - } - - // - // Fill the message object with the - // received data. - // - - Message *message = store -> getTemporary(); - - if (message == NULL) - { - #ifdef PANIC - *logofs << "handleEncodeCached: " << store -> name() - << ": PANIC! Can't allocate memory for " - << "a new message.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory for " - << "a new message in context [D].\n"; - - HandleCleanup(); - } - - // - // As we are at encoding side, it is enough to store the - // checksum for the object while data can be erased. Both - // the identity and the data will never be sent through - // the wire again as long as they are stored in the cache - // at the decoding side. The split parameter is always - // set to 0 as the data will not be stored in any case. - // - - store -> parse(message, 0, buffer, size, use_checksum, - discard_data, bigEndian_); - - #ifdef DUMP - - store -> dump(message); - - #endif - - // - // Search the object in the message - // store. If found get the position. - // - - #ifdef DEBUG - *logofs << "handleEncodeCached: " << store -> name() - << ": Searching object of size " << size - << " in the cache.\n" << logofs_flush; - #endif - - int added; - int locked; - - position = store -> findOrAdd(message, use_checksum, - discard_data, added, locked); - - if (position == nothing) - { - #ifdef WARNING - *logofs << "handleEncodeCached: " << store -> name() - << ": WARNING! Can't store object in the cache.\n" - << logofs_flush; - #endif - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeActionValue(is_discarded, - store -> lastActionCache); - - store -> lastAction = is_discarded; - - return 0; - } - else if (locked == 1) - { - // - // We can't issue a cache hit. Encoding identity - // differences while message it's being split - // would later result in agent to commit a wrong - // version of message. - // - - #ifdef WARNING - *logofs << "handleEncodeCached: " << store -> name() - << ": WARNING! Message of size " << store -> plainSize(position) - << " at position " << position << " is locked.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Message of size " << store -> plainSize(position) - << " at position " << position << " is locked.\n"; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeActionValue(is_discarded, - store -> lastActionCache); - - store -> lastAction = is_discarded; - - return 0; - } - else if (added == 1) - { - store -> resetTemporary(); - - #ifdef DEBUG - *logofs << "handleEncodeCached: " << store -> name() << ": Message of size " - << store -> plainSize(position) << " has been stored at position " - << position << ".\n" << logofs_flush; - - *logofs << "handleEncodeCached: " << store -> name() << ": There are " - << store -> getSize() << " messages in the store out of " - << store -> cacheSlots << " slots.\n" << logofs_flush; - - *logofs << "handleEncodeCached: " << store -> name() - << ": Size of store is " << store -> getLocalStorageSize() - << " bytes locally and " << store -> getRemoteStorageSize() - << " bytes remotely.\n" << logofs_flush; - - *logofs << "handleEncodeCached: " << store -> name() - << ": Size of total cache is " << store -> getLocalTotalStorageSize() - << " bytes locally and " << store -> getRemoteTotalStorageSize() - << " bytes remotely.\n" << logofs_flush; - #endif - - // - // Inform the decoding side that message - // must be inserted in cache and encode - // the position where the insertion took - // place. - // - - store -> lastAction = IS_ADDED; - - store -> lastAdded = position; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeActionValue(IS_ADDED, store -> lastAdded, - store -> lastActionCache); - - return 0; - } - else - { - #ifdef DEBUG - *logofs << "handleEncodeCached: " << store -> name() - << ": Cache hit. Found object at position " - << position << ".\n" << logofs_flush; - #endif - - // - // Must abort the connection if the - // the position is invalid. - // - - Message *cachedMessage = store -> get(position); - - // - // Increase the rating of the cached - // message. - // - - store -> touch(cachedMessage); - - #ifdef DEBUG - *logofs << "handleEncodeCached: " << store -> name() << ": Hits for " - << "object at position " << position << " are now " - << store -> getTouches(position) << ".\n" - << logofs_flush; - #endif - - // - // Send to the decoding side position - // where object can be found in cache. - // - - store -> lastAction = IS_HIT; - - store -> lastHit = position; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeActionValue(IS_HIT, store -> lastHit, - store -> lastActionCache); - - // - // Send the field by field differences in - // respect to the original message stored - // in cache. - // - - store -> updateIdentity(encodeBuffer, message, cachedMessage, channelCache); - - return 1; - } -} - -void Channel::handleUpdateAdded(MessageStore *store, unsigned int dataSize, - unsigned int compressedDataSize) -{ - #ifdef TEST - - if (store -> lastAction != IS_ADDED) - { - #ifdef PANIC - *logofs << "handleUpdateAdded: " << store -> name() - << ": PANIC! Function called for action '" - << store -> lastAction << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Update function called for " - << "store '" << store -> name() << "' with " - << "action '" << store -> lastAction - << "'.\n"; - - HandleCleanup(); - } - - #endif - - #ifdef DEBUG - *logofs << "handleUpdateAdded: " << store -> name() << ": Updating " - << "object at position " << store -> lastAdded << " of size " - << store -> plainSize(store -> lastAdded) << " (" << dataSize - << "/" << compressedDataSize << ").\n" << logofs_flush; - #endif - - store -> updateData(store -> lastAdded, dataSize, compressedDataSize); - - #ifdef DEBUG - *logofs << "handleUpdateAdded: " << store -> name() << ": There are " - << store -> getSize() << " messages in the store out of " - << store -> cacheSlots << " slots.\n" << logofs_flush; - - *logofs << "handleUpdateAdded: " << store -> name() - << ": Size of store is " << store -> getLocalStorageSize() - << " bytes locally and " << store -> getRemoteStorageSize() - << " bytes remotely.\n" << logofs_flush; - - *logofs << "handleUpdateAdded: " << store -> name() - << ": Size of total cache is " << store -> getLocalTotalStorageSize() - << " bytes locally and " << store -> getRemoteTotalStorageSize() - << " bytes remotely.\n" << logofs_flush; - #endif -} - -int Channel::handleDecodeCached(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, - MessageStore *store, unsigned char *&buffer, - unsigned int &size) -{ - // - // Create a new message object and - // fill it with received data. - // - - #ifdef DEBUG - *logofs << "handleDecodeCached: " << store -> name() - << ": Going to handle a new message of this class.\n" - << logofs_flush; - #endif - - // - // Decode bits telling how to handle - // this message. - // - - unsigned char action; - unsigned short int position; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeActionValue(action, position, - store -> lastActionCache); - - // - // Clean operations must always come - // before any operation on message. - // - - while (action == is_removed) - { - // Since ProtoStep7 (#issue 108) - store -> lastRemoved = position; - - #ifdef DEBUG - - if (store -> get(store -> lastRemoved)) - { - *logofs << "handleDecodeCached: " << store -> name() << ": Cleaning up " - << "object at position " << store -> lastRemoved - << " of size " << store -> plainSize(store -> lastRemoved) - << " (" << store -> plainSize(store -> lastRemoved) << "/" - << store -> compressedSize(store -> lastRemoved) << ").\n" - << logofs_flush; - } - - #endif - - // - // If the message can't be found we - // will abort the connection. - // - - store -> remove(store -> lastRemoved, discard_checksum, use_data); - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeActionValue(action, position, - store -> lastActionCache); - } - - // - // If it's a cache hit, the position - // where object can be found follows. - // - - if ((T_store_action) action == IS_HIT) - { - // Since ProtoStep7 (#issue 108) - store -> lastHit = position; - - // - // Get data from the cache at given position. - // - - #ifdef DEBUG - - if (store -> get(store -> lastHit)) - { - *logofs << "handleDecodeCached: " << store -> name() << ": Retrieving " - << "object at position " << store -> lastHit - << " of size " << store -> plainSize(store -> lastHit) - << " (" << store -> plainSize(store -> lastHit) << "/" - << store -> compressedSize(store -> lastHit) << ").\n" - << logofs_flush; - } - - #endif - - // - // Must abort the connection if the - // the position is invalid. - // - - Message *message = store -> get(store -> lastHit); - - // - // Make room for the outgoing message. - // - - size = store -> plainSize(store -> lastHit); - - buffer = writeBuffer_.addMessage(size); - - #ifdef DEBUG - *logofs << "handleDecodeCached: " << store -> name() - << ": Prepared an outgoing buffer of " - << size << " bytes.\n" << logofs_flush; - #endif - - // - // Decode the variant part. Pass client - // or server cache to the message store. - // - - store -> updateIdentity(decodeBuffer, message, channelCache); - - // - // Write each field in the outgoing buffer. - // - - store -> unparse(message, buffer, size, bigEndian_); - - #ifdef DUMP - - store -> dump(message); - - #endif - - store -> lastAction = IS_HIT; - - return 1; - } - else if ((T_store_action) action == IS_ADDED) - { - // Since ProtoStep7 (#issue 108) - store -> lastAdded = position; - - #ifdef DEBUG - *logofs << "handleDecodeCached: " << store -> name() - << ": Message will be later stored at position " - << store -> lastAdded << ".\n" << logofs_flush; - #endif - - store -> lastAction = IS_ADDED; - - return 0; - } - else - { - #ifdef DEBUG - *logofs << "handleDecodeCached: " << store -> name() - << ": Message will be later discarded.\n" - << logofs_flush; - #endif - - store -> lastAction = is_discarded; - - return 0; - } -} - -void Channel::handleSaveAdded(MessageStore *store, int split, unsigned char *buffer, - unsigned int size, const unsigned char *compressedData, - const unsigned int compressedDataSize) -{ - #ifdef TEST - - if (store -> lastAction != IS_ADDED) - { - #ifdef PANIC - *logofs << "handleSaveAdded: " << store -> name() - << ": PANIC! Function called for action '" - << store -> lastAction << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Save function called for " - << "store '" << store -> name() << "' with " - << "action '" << store -> lastAction - << "'.\n"; - - HandleCleanup(); - } - - #endif - - Message *message = store -> getTemporary(); - - if (message == NULL) - { - #ifdef PANIC - *logofs << "handleSaveAdded: " << store -> name() - << ": PANIC! Can't access temporary storage " - << "for message at position " << store -> lastAdded - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't access temporary storage " - << "for message at position " << store -> lastAdded - << ".\n"; - - HandleCleanup(); - } - - if (compressedData == NULL) - { - // - // If the data part has been split - // avoid to copy it into the message. - // - - store -> parse(message, split, buffer, size, discard_checksum, - use_data, bigEndian_); - } - else - { - store -> parse(message, buffer, size, compressedData, - compressedDataSize, discard_checksum, - use_data, bigEndian_); - } - - if (store -> add(message, store -> lastAdded, - discard_checksum, use_data) == nothing) - { - #ifdef PANIC - *logofs << "handleSaveAdded: " << store -> name() - << ": PANIC! Can't store message in the cache " - << "at position " << store -> lastAdded << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't store message of type " - << store -> name() << "in the cache at position " - << store -> lastAdded << ".\n"; - - HandleCleanup(); - } - else - { - store -> resetTemporary(); - - #ifdef DEBUG - *logofs << "handleSaveAdded: " << store -> name() << ": Stored " - << (compressedData == NULL ? "plain" : "compressed") - << " object at position " << store -> lastAdded - << " of size " << store -> plainSize(store -> lastAdded) - << " (" << store -> plainSize(store -> lastAdded) << "/" - << store -> compressedSize(store -> lastAdded) << ").\n" - << logofs_flush; - #endif - } - - #ifdef DEBUG - *logofs << "handleSaveAdded: " << store -> name() - << ": Size of store is " << store -> getLocalStorageSize() - << " bytes locally and " << store -> getRemoteStorageSize() - << " bytes remotely.\n" << logofs_flush; - - *logofs << "handleSaveAdded: " << store -> name() - << ": Size of total cache is " << store -> getLocalTotalStorageSize() - << " bytes locally and " << store -> getRemoteTotalStorageSize() - << " bytes remotely.\n" << logofs_flush; - #endif -} - -int Channel::handleWait(int timeout) -{ - #ifdef TEST - *logofs << "handleWait: Going to wait for more data " - << "on FD#" << fd_ << " at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - T_timestamp startTs = getNewTimestamp(); - - T_timestamp nowTs = startTs; - - int readable; - int remaining; - - for (;;) - { - remaining = timeout - diffTimestamp(startTs, nowTs); - - if (transport_ -> blocked() == 1) - { - #ifdef WARNING - *logofs << "handleWait: WARNING! Having to drain with " - << "channel " << "for FD#" << fd_ << " blocked.\n" - << logofs_flush; - #endif - - handleDrain(0, remaining); - - continue; - } - - if (remaining <= 0) - { - #ifdef TEST - *logofs << "handleWait: Timeout raised while waiting " - << "for more data for FD#" << fd_ << " at " - << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - return 0; - } - - #ifdef TEST - *logofs << "handleWait: Waiting " << remaining << " Ms " - << "for a new message on FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - readable = transport_ -> wait(remaining); - - if (readable > 0) - { - #ifdef TEST - *logofs << "handleWait: WARNING! Encoding more data " - << "for FD#" << fd_ << " at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - if (proxy -> handleAsyncRead(fd_) < 0) - { - return -1; - } - - return 1; - } - else if (readable == -1) - { - return -1; - } - - nowTs = getNewTimestamp(); - } -} - -int Channel::handleDrain(int limit, int timeout) -{ - #ifdef TEST - *logofs << "handleDrain: Going to drain FD#" << fd_ - << " with a limit of " << limit << " bytes " - << "at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - T_timestamp startTs = getNewTimestamp(); - - T_timestamp nowTs = startTs; - - int drained; - int remaining; - - int result; - - for (;;) - { - remaining = timeout - diffTimestamp(startTs, nowTs); - - if (remaining <= 0) - { - #ifdef TEST - *logofs << "handleDrain: Timeout raised while draining " - << "FD#" << fd_ << " at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - result = 0; - - goto ChannelDrainEnd; - } - - #ifdef TEST - *logofs << "handleDrain: Trying to write to FD#" - << fd_ << " with " << remaining << " Ms " - << "remaining.\n" << logofs_flush; - #endif - - drained = transport_ -> drain(limit, remaining); - - if (drained == 1) - { - #ifdef TEST - *logofs << "handleDrain: Transport for FD#" << fd_ - << " drained to " << transport_ -> length() - << " bytes at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - result = 1; - - goto ChannelDrainEnd; - } - else if (drained == 0 && transport_ -> readable() > 0) - { - #ifdef TEST - *logofs << "handleDrain: WARNING! Encoding more data " - << "for FD#" << fd_ << " at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - if (proxy -> handleAsyncRead(fd_) < 0) - { - goto ChannelDrainError; - } - } - else if (drained == -1) - { - goto ChannelDrainError; - } - - nowTs = getNewTimestamp(); - - if (diffTimestamp(startTs, nowTs) >= control -> ChannelTimeout) - { - int seconds = (remaining + control -> LatencyTimeout * 10) / 1000; - - #ifdef WARNING - *logofs << "handleDrain: WARNING! Could not drain FD#" - << fd_ << " within " << seconds << " seconds.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Can't write to connection on FD#" - << fd_ << " since " << seconds << " seconds.\n"; - - if (alert_ == 0) - { - if (control -> ProxyMode == proxy_client) - { - alert_ = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT; - } - else - { - alert_ = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT; - } - - HandleAlert(alert_, 1); - } - } - } - -ChannelDrainEnd: - - // - // Maybe we drained the channel and are - // now out of the congestion state. - // - - handleCongestion(); - - return result; - -ChannelDrainError: - - finish_ = 1; - - return -1; -} - -int Channel::handleCongestion() -{ - // - // Send a begin congestion control code - // if the local end of the channel does - // not consume its data. - // - - if (isCongested() == 1) - { - if (congestion_ == 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleCongestion: Sending congestion for FD#" - << fd_ << " with length " << transport_ -> length() - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - congestion_ = 1; - - // - // Use the callback to send the control - // code immediately. - // - - if (proxy -> handleAsyncCongestion(fd_) < 0) - { - finish_ = 1; - - return -1; - } - } - } - else - { - // - // If the channel was in congestion state - // send an end congestion control code. - // - - if (congestion_ == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleCongestion: Sending decongestion for FD#" - << fd_ << " with length " << transport_ -> length() - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - congestion_ = 0; - - if (proxy -> handleAsyncDecongestion(fd_) < 0) - { - finish_ = 1; - - return -1; - } - } - - // - // Remove the "channel unresponsive" - // dialog. - // - - if (alert_ != 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleCongestion: Displacing the dialog " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - HandleAlert(DISPLACE_MESSAGE_ALERT, 1); - } - } - - return 1; -} - -int Channel::handleFlush(T_flush type, int bufferLength, int scratchLength) -{ - if (finish_ == 1) - { - #ifdef TEST - *logofs << "handleFlush: Not flushing data for " - << "finishing channel for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - writeBuffer_.fullReset(); - - return -1; - } - - #ifdef TEST - *logofs << "handleFlush: Flushing " << bufferLength - << " + " << scratchLength << " bytes " - << "to FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - // - // Check if the channel has data available. - // Recent Linux kernels are very picky. - // They require that we read often or they - // assume that the process is non-interact- - // ive. - // - - int result = 0; - - if (handleAsyncEvents() < 0) - { - goto ChannelFlushError; - } - - // - // Write the data in the main buffer first, - // followed by the data in the scratch buffer. - // - - if (bufferLength > 0) - { - result = transport_ -> write(write_immediate, - writeBuffer_.getData(), bufferLength); - } - - if (result >= 0 && scratchLength > 0) - { - result = transport_ -> write(write_immediate, - writeBuffer_.getScratchData(), scratchLength); - } - - if (type == flush_if_any) - { - writeBuffer_.fullReset(); - } - else - { - writeBuffer_.partialReset(); - } - - // - // If we failed to write to the X connection then - // set the finish flag. The caller should continue - // to handle all the remaining messages or it will - // corrupt the decode buffer. At the real end, an - // error will be propagated to the upper layers - // which will perform any needed cleanup. - // - - if (result < 0) - { - goto ChannelFlushError; - } - - // - // Reset transport buffers. - // - - transport_ -> partialReset(); - - // - // Check if the X server has generated - // any event in response to our data. - // - - if (handleAsyncEvents() < 0) - { - goto ChannelFlushError; - } - - // - // Check if the channel has entered in - // congestion state and, in this case, - // send an immediate congestion control - // code to the remote. - // - - handleCongestion(); - - // - // We could optionally drain the output - // buffer if this is X11 channel. - // - // if (isCongested() == 1 && isReliable() == 1) - // { - // if (handleDrain(0, control -> ChannelTimeout) < 0) - // { - // goto ChannelFlushError; - // } - // } - // - - return 1; - -ChannelFlushError: - - finish_ = 1; - - return -1; -} - -int Channel::handleFlush() -{ - #ifdef TEST - *logofs << "handleFlush: Flushing " - << transport_ -> length() << " bytes to FD#" - << fd_ << " with descriptor writable.\n" - << logofs_flush; - #endif - - // - // Check if there is anything to read - // before anf after having written to - // the socket. - // - - if (handleAsyncEvents() < 0) - { - goto ChannelFlushError; - } - - if (transport_ -> flush() < 0) - { - #ifdef TEST - *logofs << "handleFlush: Failure detected " - << "flushing data to FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - goto ChannelFlushError; - } - - if (handleAsyncEvents() < 0) - { - goto ChannelFlushError; - } - - // - // Reset channel's transport buffers. - // - - transport_ -> partialReset(); - - // - // Check if the channel went out of the - // congestion state. - // - - handleCongestion(); - - return 1; - -ChannelFlushError: - - finish_ = 1; - - return -1; -} - -void Channel::handleResetAlert() -{ - if (alert_ != 0) - { - #ifdef TEST - *logofs << "handleResetAlert: The channel alert '" - << alert_ << "' was displaced.\n" - << logofs_flush; - #endif - - alert_ = 0; - } -} - -int Channel::handleCompress(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned int offset, const unsigned char *buffer, - const unsigned int size, unsigned char *&compressedData, - unsigned int &compressedDataSize) -{ - if (size <= offset) - { - #ifdef DEBUG - *logofs << "handleCompress: Not compressing data for FD#" << fd_ - << " as offset is " << offset << " with data size " - << size << ".\n" << logofs_flush; - #endif - - return 0; - } - - #ifdef DEBUG - *logofs << "handleCompress: Compressing data for FD#" << fd_ - << " with data size " << size << " and offset " - << offset << ".\n" << logofs_flush; - #endif - - // - // It is responsibility of the compressor to - // mark the buffer as such if the compression - // couldn't take place. - // - - if (compressor_ -> compressBuffer(buffer + offset, size - offset, compressedData, - compressedDataSize, encodeBuffer) <= 0) - { - #ifdef DEBUG - *logofs << "handleCompress: Sent " << size - offset - << " bytes of plain data for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - return 0; - } - else - { - #ifdef DEBUG - *logofs << "handleCompress: Sent " << compressedDataSize - << " bytes of compressed data for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - return 1; - } -} - -int Channel::handleDecompress(DecodeBuffer &decodeBuffer, const unsigned char opcode, - const unsigned int offset, unsigned char *buffer, - const unsigned int size, const unsigned char *&compressedData, - unsigned int &compressedDataSize) -{ - if (size <= offset) - { - return 0; - } - - int result = compressor_ -> decompressBuffer(buffer + offset, size - offset, - compressedData, compressedDataSize, - decodeBuffer); - if (result < 0) - { - #ifdef PANIC - *logofs << "handleDecompress: PANIC! Failed to decompress " - << size - offset << " bytes of data for FD#" << fd_ - << " with OPCODE#" << (unsigned int) opcode << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Data decompression failed for OPCODE#" - << (unsigned int) opcode << ".\n"; - - return -1; - } - else if (result == 0) - { - #ifdef DEBUG - *logofs << "handleDecompress: Received " << size - offset - << " bytes of plain data for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - return 0; - } - else - { - #ifdef DEBUG - *logofs << "handleDecompress: Received " << compressedDataSize - << " bytes of compressed data for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - return 1; - } -} - -int Channel::handleCleanAndNullRequest(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size) -{ - #ifdef TEST - *logofs << "handleCleanAndNullRequest: Removing the previous data " - << "and sending an X_NoOperation " << "for FD#" << fd_ - << " due to OPCODE#" << (unsigned int) opcode << " (" - << DumpOpcode(opcode) << ").\n" << logofs_flush; - #endif - - writeBuffer_.removeMessage(size - 4); - - size = 4; - opcode = X_NoOperation; - - return 1; -} - -int Channel::handleNullRequest(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size) -{ - #ifdef TEST - *logofs << "handleNullRequest: Sending an X_NoOperation for FD#" - << fd_ << " due to OPCODE#" << (unsigned int) opcode - << " (" << DumpOpcode(opcode) << ").\n" - << logofs_flush; - #endif - - size = 4; - buffer = writeBuffer_.addMessage(size); - opcode = X_NoOperation; - - return 1; -} - -void Channel::handleSplitStoreError(int resource) -{ - if (resource < 0 || resource >= CONNECTIONS_LIMIT) - { - #ifdef PANIC - *logofs << "handleSplitStoreError: PANIC! Resource " - << resource << " is out of range with limit " - << "set to " << CONNECTIONS_LIMIT << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Resource " << resource - << " is out of range with limit set to " - << CONNECTIONS_LIMIT << ".\n"; - - HandleCleanup(); - } - else - { - #ifdef PANIC - *logofs << "handleSplitStoreError: PANIC! Cannot " - << "allocate the split store for resource " - << resource << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot allocate the " - << "split store for resource " << resource - << ".\n"; - - HandleCleanup(); - } -} - -void Channel::handleSplitStoreAlloc(List *list, int resource) -{ - if (resource < 0 || resource >= CONNECTIONS_LIMIT) - { - handleSplitStoreError(resource); - } - - if (clientStore_ -> getSplitStore(resource) == NULL) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitStoreAlloc: Allocating a new " - << "split store for resource " << resource - << ".\n" << logofs_flush; - #endif - - SplitStore *splitStore = clientStore_ -> createSplitStore(resource); - - if (splitStore == NULL) - { - handleSplitStoreError(resource); - } - - list -> add(resource); - } - #if defined(TEST) || defined(SPLIT) - else - { - // - // Old proxy versions only use a single - // split store. - // - - if (resource != 0) - { - *logofs << "handleSplitStoreAlloc: WARNING! A split " - << "store for resource " << resource - << " already exists.\n" << logofs_flush; - } - } - #endif -} - -void Channel::handleSplitStoreRemove(List *list, int resource) -{ - if (resource < 0 || resource >= CONNECTIONS_LIMIT) - { - handleSplitStoreError(resource); - } - - SplitStore *splitStore = clientStore_ -> getSplitStore(resource); - - if (splitStore != NULL) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitStoreRemove: Deleting the " - << "split store for resource " << resource - << ".\n" << logofs_flush; - #endif - - clientStore_ -> destroySplitStore(resource); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitStoreRemove: Deleting resource " - << resource << " from the list " << ".\n" - << logofs_flush; - #endif - - list -> remove(resource); - } - #if defined(TEST) || defined(SPLIT) - else - { - *logofs << "handleSplitStoreRemove: WARNING! A split " - << "store for resource " << resource - << " does not exist.\n" << logofs_flush; - } - #endif -} - -Split *Channel::handleSplitCommitRemove(int request, int resource, int position) -{ - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitCommitRemove: SPLIT! Checking split " - << "commit with resource " << resource << " request " - << request << " and position " << position - << ".\n" << logofs_flush; - #endif - - // - // Remove the split from the split queue. - // - - CommitStore *commitStore = clientStore_ -> getCommitStore(); - - Split *split = commitStore -> pop(); - - if (split == NULL) - { - #ifdef PANIC - *logofs << "handleSplitCommitRemove: PANIC! Can't " - << "find the split in the commit queue.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't find the " - << "split in the commit queue.\n"; - - HandleCleanup(); - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitCommitRemove: SPLIT! Element from " - << "the queue has resource " << split -> getResource() - << " request " << split -> getRequest() << " and " - << "position " << split -> getPosition() - << ".\n" << logofs_flush; - #endif - - // Since ProtoStep7 (#issue 108) - if (resource != split -> getResource() || - request != split -> getRequest() || - position != split -> getPosition()) - { - #ifdef PANIC - *logofs << "handleSplitCommitRemove: PANIC! The data in " - << "the split doesn't match the commit request.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": The data in the split doesn't " - << "match the commit request.\n"; - - return NULL; - } - - #if defined(TEST) || defined(SPLIT) - - commitStore -> dump(); - - #endif - - return split; -} - -int Channel::setReferences() -{ - #ifdef TEST - *logofs << "Channel: Initializing the static " - << "members for the base class.\n" - << logofs_flush; - #endif - - firstClient_ = -1; - - fontPort_ = -1; - - #ifdef REFERENCES - - references_ = 0; - - #endif - - return 1; -} - -int Channel::setOpcodes(OpcodeStore *opcodeStore) -{ - opcodeStore_ = opcodeStore; - - #ifdef TEST - *logofs << "setOpcodes: Propagated opcodes store to channel " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - return 1; -} - -int Channel::setStores(ClientStore *clientStore, ServerStore *serverStore) -{ - clientStore_ = clientStore; - serverStore_ = serverStore; - - #ifdef TEST - *logofs << "setStores: Propagated message stores to channel " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - return 1; -} - -int Channel::setCaches(ClientCache *clientCache, ServerCache *serverCache) -{ - clientCache_ = clientCache; - serverCache_ = serverCache; - - #ifdef TEST - *logofs << "setCaches: Propagated encode caches to channel " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - return 1; -} diff --git a/nxcomp/Channel.h b/nxcomp/Channel.h deleted file mode 100644 index 93b022630..000000000 --- a/nxcomp/Channel.h +++ /dev/null @@ -1,664 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Channel_H -#define Channel_H - -#include "Transport.h" - -#include "WriteBuffer.h" - -#include "OpcodeStore.h" - -#include "ClientStore.h" -#include "ServerStore.h" - -#include "ClientCache.h" -#include "ServerCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Forward declaration of referenced classes. -// - -class List; - -class StaticCompressor; - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Define this to log a line when a channel -// is created or destroyed. -// - -#undef REFERENCES - -// -// Type of traffic carried by channel. -// - -typedef enum -{ - channel_none = -1, - channel_x11, - channel_cups, - channel_smb, - channel_media, - channel_http, - channel_font, - channel_slave, - channel_last_tag - -} T_channel_type; - -// -// Type of notification event to be sent -// by proxy to the X channel. -// - -typedef enum -{ - notify_no_split, - notify_start_split, - notify_commit_split, - notify_end_split, - notify_empty_split, - -} T_notification_type; - -class Channel -{ - public: - - // - // Maximum number of X connections supported. - // - - static const int CONNECTIONS_LIMIT = 256; - - Channel(Transport *transport, StaticCompressor *compressor); - - virtual ~Channel(); - - // - // Read any X message available on the X - // connection and encode it to the encode - // buffer. - // - - virtual int handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, - unsigned int length) = 0; - - // - // Decode any X message encoded in the - // proxy message and write it to the X - // connection. - // - - virtual int handleWrite(const unsigned char *message, unsigned int length) = 0; - - // - // Other methods to be implemented in - // client, server and generic channel - // classes. - // - - virtual int handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, - T_store_action action, int position, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) = 0; - - virtual int handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, - T_store_action action, int position, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) = 0; - - virtual int handleSplit(EncodeBuffer &encodeBuffer) = 0; - - virtual int handleSplit(DecodeBuffer &decodeBuffer) = 0; - - virtual int handleSplitEvent(EncodeBuffer &encodeBuffer, Split *split) = 0; - - virtual int handleSplitEvent(DecodeBuffer &decodeBuffer) = 0; - - virtual int handleMotion(EncodeBuffer &encodeBuffer) = 0; - - virtual int handleCompletion(EncodeBuffer &encodeBuffer) = 0; - - virtual int handleConfiguration() = 0; - - virtual int handleFinish() = 0; - - // - // Interleave reads of the available - // events while writing data to the - // channel socket. - // - - virtual int handleAsyncEvents() = 0; - - // - // Handle the channel tear down. - // - - int handleClosing() - { - closing_ = 1; - - return 1; - } - - int handleDrop() - { - drop_ = 1; - - return 1; - } - - // - // Try to read more data from the socket. In - // the meanwhile flush any enqueued data if - // the channel is blocked. Return as soon as - // more data has been read or the timeout has - // been exceeded. - // - - int handleWait(int timeout); - - // - // Drain the output buffer while handling the - // data that may become readable. - // - - int handleDrain(int timeout, int limit); - - // - // Flush any remaining data in the transport - // buffer. - // - - int handleFlush(); - - // - // Called when the loop has replaced or - // closed a previous alert. - // - - void handleResetAlert(); - - // - // Initialize all the static members. - // - - static int setReferences(); - - // - // Set pointer to object mapping opcodes - // of NX specific messages. - // - - int setOpcodes(OpcodeStore *opcodeStore); - - // - // Update pointers to message stores in - // channels. - // - - int setStores(ClientStore *clientStore, ServerStore *serverStore); - - // - // The same for channels caches. - // - - int setCaches(ClientCache *clientCache, ServerCache *serverCache); - - // - // Set the port used for tunneling of the - // font server connections. - // - - void setPorts(int fontPort) - { - fontPort_ = fontPort; - } - - // - // Check if there are pending split - // to send to the remote side. - // - - virtual int needSplit() const = 0; - - // - // Check if there are motion events - // to flush. - // - - virtual int needMotion() const = 0; - - // - // Return the type of traffic carried - // by this channel. - // - - virtual T_channel_type getType() const = 0; - - // - // Check if the channel has been marked - // as closing down. - // - - int getFinish() const - { - return finish_; - } - - int getClosing() - { - return closing_; - } - - int getDrop() - { - return drop_; - } - - int getCongestion() - { - return congestion_; - } - - protected: - - int handleFlush(T_flush type) - { - // - // We could write the data immediately if there - // is already something queued to the low level - // TCP buffers. - // - // if (... || transport_ -> queued() > 0) - // { - // ... - // } - // - - if (writeBuffer_.getScratchLength() > 0 || - (type == flush_if_any && writeBuffer_.getLength() > 0) || - writeBuffer_.getLength() >= (unsigned int) - control -> TransportFlushBufferSize) - { - return handleFlush(type, writeBuffer_.getLength(), - writeBuffer_.getScratchLength()); - } - - return 0; - } - - // - // Actually flush the data to the - // channel descriptor. - // - - int handleFlush(T_flush type, int bufferLength, int scratchLength); - - // - // Handle the congestion changes. - // - - int handleCongestion(); - - // - // Encode and decode X messages. - // - - int handleEncode(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, - MessageStore *store, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - int handleDecode(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, - MessageStore *store, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - // - // Encode the message based on its - // message store. - // - - int handleEncodeCached(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, - MessageStore *store, const unsigned char *buffer, - const unsigned int size); - - int handleDecodeCached(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, - MessageStore *store, unsigned char *&buffer, - unsigned int &size); - - int handleEncodeIdentity(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, - MessageStore *store, const unsigned char *buffer, - const unsigned int size, int bigEndian) - { - return (store -> encodeIdentity(encodeBuffer, buffer, size, - bigEndian, channelCache)); - } - - int handleDecodeIdentity(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, - MessageStore *store, unsigned char *&buffer, - unsigned int &size, int bigEndian, - WriteBuffer *writeBuffer) - { - return (store -> decodeIdentity(decodeBuffer, buffer, size, bigEndian, - writeBuffer, channelCache)); - } - - // - // Other utility functions used by - // the encoding and decoding methods. - // - - void handleCopy(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned int offset, const unsigned char *buffer, - const unsigned int size) - { - if (size > offset) - { - encodeBuffer.encodeMemory(buffer + offset, size - offset); - } - } - - void handleCopy(DecodeBuffer &decodeBuffer, const unsigned char opcode, - const unsigned int offset, unsigned char *buffer, - const unsigned int size) - { - if (size > offset) - { - memcpy(buffer + offset, decodeBuffer.decodeMemory(size - offset), size - offset); - } - } - - void handleUpdate(MessageStore *store, const unsigned int dataSize, - const unsigned int compressedDataSize) - { - if (store -> lastAction == IS_ADDED) - { - handleUpdateAdded(store, dataSize, compressedDataSize); - } - } - - void handleSave(MessageStore *store, unsigned char *buffer, unsigned int size, - const unsigned char *compressedData = NULL, - const unsigned int compressedDataSize = 0) - { - if (store -> lastAction == IS_ADDED) - { - handleSaveAdded(store, 0, buffer, size, compressedData, compressedDataSize); - } - } - - void handleSaveSplit(MessageStore *store, unsigned char *buffer, - unsigned int size) - { - if (store -> lastAction == IS_ADDED) - { - return handleSaveAdded(store, 1, buffer, size, 0, 0); - } - } - - void handleUpdateAdded(MessageStore *store, const unsigned int dataSize, - const unsigned int compressedDataSize); - - void handleSaveAdded(MessageStore *store, int split, unsigned char *buffer, - unsigned int size, const unsigned char *compressedData, - const unsigned int compressedDataSize); - - // - // Compress the data part of a message - // using ZLIB or another compressor - // and send it over the network. - // - - int handleCompress(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned int offset, const unsigned char *buffer, - const unsigned int size, unsigned char *&compressedData, - unsigned int &compressedDataSize); - - int handleDecompress(DecodeBuffer &decodeBuffer, const unsigned char opcode, - const unsigned int offset, unsigned char *buffer, - const unsigned int size, const unsigned char *&compressedData, - unsigned int &compressedDataSize); - - // - // Send an X_NoOperation to the X server. - // The second version also removes any - // previous data in the write buffer. - // - - int handleNullRequest(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size); - - int handleCleanAndNullRequest(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size); - - // - // X11 channels are considered to be in - // congestion state when there was a - // blocking write and, since then, the - // local end didn't consume all the data. - // - - virtual int isCongested() - { - return (transport_ -> getType() != - transport_agent && transport_ -> length() > - control -> TransportFlushBufferSize); - } - - virtual int isReliable() - { - return 1; - } - - // - // Determine how to handle allocation - // of new messages in the message - // stores. - // - - int mustCleanStore(MessageStore *store) - { - return (store -> getRemoteTotalStorageSize() > control -> - RemoteTotalStorageSize || store -> getLocalTotalStorageSize() > - control -> LocalTotalStorageSize || (store -> getRemoteStorageSize() > - (control -> RemoteTotalStorageSize / 100 * store -> - cacheThreshold)) || (store -> getLocalStorageSize() > - (control -> LocalTotalStorageSize / 100 * store -> - cacheThreshold))); - } - - int canCleanStore(MessageStore *store) - { - return ((store -> getSize() > 0 && (store -> getRemoteStorageSize() > - (control -> RemoteTotalStorageSize / 100 * store -> - cacheLowerThreshold))) || (store -> getLocalStorageSize() > - (control -> LocalTotalStorageSize / 100 * store -> - cacheLowerThreshold))); - } - - protected: - - // - // Set up the split stores. - // - - void handleSplitStoreError(int resource); - - void handleSplitStoreAlloc(List *list, int resource); - void handleSplitStoreRemove(List *list, int resource); - - Split *handleSplitCommitRemove(int request, int resource, int position); - - void validateSize(const char *name, int input, int output, - int offset, int size) - { - if (size < offset || size > control -> MaximumMessageSize || - size != (int) RoundUp4(input) + offset || - output > control -> MaximumMessageSize) - { - *logofs << "Channel: PANIC! Invalid size " << size - << " for " << name << " output with data " - << input << "/" << output << "/" << offset - << "/" << size << ".\n" << logofs_flush; - - cerr << "Error" << ": Invalid size " << size - << " for " << name << " output.\n"; - - HandleAbort(); - } - } - - // - // Is the X client big endian? - // - - int bigEndian() const - { - return bigEndian_; - } - - int bigEndian_; - - // - // Other X server's features - // saved at session startup. - // - - unsigned int imageByteOrder_; - unsigned int bitmapBitOrder_; - unsigned int scanlineUnit_; - unsigned int scanlinePad_; - - int firstRequest_; - int firstReply_; - - // - // Use this class for IO operations. - // - - Transport *transport_; - - // - // The static compressor is created by the - // proxy and shared among channels. - // - - StaticCompressor *compressor_; - - // - // Map NX operations to opcodes. Propagated - // by proxy to all channels on the same X - // server. - // - - OpcodeStore *opcodeStore_; - - // - // Also stores are shared between channels. - // - - ClientStore *clientStore_; - ServerStore *serverStore_; - - // - // Caches are specific for each channel. - // - - ClientCache *clientCache_; - ServerCache *serverCache_; - - // - // Data going to X connection. - // - - WriteBuffer writeBuffer_; - - // - // Other data members. - // - - int fd_; - - int finish_; - int closing_; - int drop_; - int congestion_; - int priority_; - - int alert_; - - // - // It will be set to the descriptor of the - // first X channel that is successfully con- - // nected and will print an info message on - // standard error. - // - - static int firstClient_; - - // - // Port used for font server connections. - // - - static int fontPort_; - - // - // Track which cache operations have been - // enabled by the agent. - // - - int enableCache_; - int enableSplit_; - int enableSave_; - int enableLoad_; - - // - // Keep track of object creation and - // deletion. - // - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -#endif /* Channel_H */ diff --git a/nxcomp/ChannelCache.cpp b/nxcomp/ChannelCache.cpp deleted file mode 100644 index 5c4c360b9..000000000 --- a/nxcomp/ChannelCache.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ChannelCache.h" - -const unsigned int CONFIGUREWINDOW_FIELD_WIDTH[7] = -{ - 16, // x - 16, // y - 16, // width - 16, // height - 16, // border width - 29, // sibling window - 3 // stack mode -}; - -const unsigned int CREATEGC_FIELD_WIDTH[23] = -{ - 4, // function - 32, // plane mask - 32, // foreground - 32, // background - 16, // line width - 2, // line style - 2, // cap style - 2, // join style - 2, // fill style - 1, // fill rule - 29, // tile - 29, // stipple - 16, // tile/stipple x origin - 16, // tile/stipple y origin - 29, // font - 1, // subwindow mode - 1, // graphics exposures - 16, // clip x origin - 16, // clip y origin - 29, // clip mask - 16, // card offset - 8, // dashes - 1 // arc mode -}; diff --git a/nxcomp/ChannelCache.h b/nxcomp/ChannelCache.h deleted file mode 100644 index 6a29c3847..000000000 --- a/nxcomp/ChannelCache.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ChannelCache_H -#define ChannelCache_H - -// -// Sizes of optional fields for ConfigureWindow -// request. -// - -extern const unsigned int CONFIGUREWINDOW_FIELD_WIDTH[7]; - -// -// Sizes of optional fields for CreateGC request. -// - -extern const unsigned int CREATEGC_FIELD_WIDTH[23]; - -// -// This is just needed to provide a pointer -// to the base cache class in encoding and -// decoding procedures of message stores. -// - -class ChannelCache -{ - public: - - ChannelCache() - { - } - - ~ChannelCache() - { - } -}; - -#endif /* ChannelCache_H */ diff --git a/nxcomp/ChannelEndPoint.cpp b/nxcomp/ChannelEndPoint.cpp deleted file mode 100644 index 286210dc7..000000000 --- a/nxcomp/ChannelEndPoint.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include -#include - -#include "ChannelEndPoint.h" - -#include "NXalert.h" - -ChannelEndPoint::ChannelEndPoint(const char *spec) - : defaultTCPPort_(0), defaultTCPInterface_(0), - defaultUnixPath_(NULL), spec_(NULL) { - setSpec(spec); -} - -ChannelEndPoint::~ChannelEndPoint() -{ - char *unixPath = NULL; - - if (getUnixPath(&unixPath)) - { - struct stat st; - lstat(unixPath, &st); - if(S_ISSOCK(st.st_mode)) - unlink(unixPath); - } -} - -void -ChannelEndPoint::setSpec(const char *spec) { - if (spec_) free(spec_); - - if (spec && strlen(spec)) - { - spec_ = strdup(spec); - isUnix_ = getUnixPath(); - isTCP_ = getTCPHostAndPort(); - } - else - { - spec_ = NULL; - isUnix_ = false; - isTCP_ = false; - } -} - -void -ChannelEndPoint::setSpec(long port) { - if (port >= 0) { - char tmp[20]; - sprintf(tmp, "%ld", port); - setSpec(tmp); - } - else { - disable(); - } -} - -void -ChannelEndPoint::setSpec(const char *hostName, long port) { - int length; - - if (spec_) free(spec_); - isUnix_ = false; - isTCP_ = false; - - if (hostName && strlen(hostName) && port >= 1) - { - length = snprintf(NULL, 0, "tcp:%s:%ld", hostName, port); - spec_ = (char *)calloc(length + 1, sizeof(char)); - snprintf(spec_, length+1, "tcp:%s:%ld", hostName, port); - isTCP_ = true; - } - else setSpec((char*)NULL); -} - -bool -ChannelEndPoint::getSpec(char **socketUri) const { - - if (socketUri) *socketUri = NULL; - - char *unixPath = NULL; - char *hostName = NULL; - long port = -1; - - char *newSocketUri = NULL; - int length = -1; - - if (getUnixPath(&unixPath)) - { - length = snprintf(NULL, 0, "unix:%s", unixPath); - } - else if (getTCPHostAndPort(&hostName, &port)) - { - length = snprintf(NULL, 0, "tcp:%s:%ld", hostName, port); - } - - if (length > 0) - { - newSocketUri = (char *)calloc(length + 1, sizeof(char)); - if (isUnixSocket()) - snprintf(newSocketUri, length+1, "unix:%s", unixPath); - else - snprintf(newSocketUri, length+1, "tcp:%s:%ld", hostName, port); - - if (socketUri) - *socketUri = strdup(newSocketUri); - } - - free(newSocketUri); - free(unixPath); - free(hostName); - - if (NULL != *socketUri) - return true; - - return false; -} - -void -ChannelEndPoint::setDefaultTCPPort(long port) { - defaultTCPPort_ = port; -} - -void -ChannelEndPoint::setDefaultTCPInterface(int publicInterface) { - defaultTCPInterface_ = publicInterface; -} - -void -ChannelEndPoint::setDefaultUnixPath(char *path) { - if (defaultUnixPath_) free(defaultUnixPath_); - - if (path && strlen(path)) - defaultUnixPath_ = strdup(path); - else - defaultUnixPath_ = NULL; -} - -void -ChannelEndPoint::disable() { - setSpec("0"); -} - -bool -ChannelEndPoint::getPort(long *port) const { - if (port) *port = 0; - long p = -1; - if (spec_) { - char *end; - p = strtol(spec_, &end, 10); - if ((end == spec_) || (*end != '\0')) - return false; - } - - if (port) *port = p; - return true; -} - -bool -ChannelEndPoint::getUnixPath(char **unixPath) const { - - if (unixPath) *unixPath = 0; - - long p; - char *path = NULL; - - if (getPort(&p)) { - if (p != 1) return false; - } - else if (spec_ && (strncmp("unix:", spec_, 5) == 0)) { - path = spec_ + 5; - } - else - return false; - - if (!path || (*path == '\0')) { - path = defaultUnixPath_; - if (!path) - return false; - } - - if (unixPath) - *unixPath = strdup(path); - - return true; -} - -bool -ChannelEndPoint::isUnixSocket() const { - return isUnix_; -} - -// FIXME!!! -static const char * -getComputerName() { - // - // Strangely enough, under some Windows OSes SMB - // service doesn't bind to localhost. Fall back - // to localhost if can't find computer name in - // the environment. In future we should try to - // bind to localhost and then try the other IPs. - // - - const char *hostname = NULL; - - #ifdef __CYGWIN32__ - - hostname = getenv("COMPUTERNAME"); - - #endif - - if (hostname == NULL) - { - hostname = "localhost"; - } - - return hostname; -} - -bool -ChannelEndPoint::getTCPHostAndPort(char **host, long *port) const { - long p; - char *h = NULL; - ssize_t h_len; - - if (host) *host = NULL; - if (port) *port = 0; - - if (getPort(&p)) { - h_len = 0; - } - else if (spec_ && (strncmp("tcp:", spec_, 4) == 0)) { - h = spec_ + 4; - char *colon = strrchr(h, ':'); - if (colon) { - char *end; - h_len = colon++ - h; - p = strtol(colon, &end, 10); - if ((end == colon) || (*end != '\0')) - return false; - } - else { - h_len = strlen(h); - p = 1; - } - } - else - return false; - - if (p == 1) p = defaultTCPPort_; - if (p < 1) return false; - - if (port) - *port = p; - - if (host) - *host = ( h_len - ? strndup(h, h_len) - : strdup(defaultTCPInterface_ ? getComputerName() : "localhost")); - - return true; -} - -bool -ChannelEndPoint::isTCPSocket() const { - return isTCP_; -} - -long ChannelEndPoint::getTCPPort() const { - long port; - if (getTCPHostAndPort(NULL, &port)) return port; - return -1; -} - -bool -ChannelEndPoint::enabled() const { - return (isUnixSocket() || isTCPSocket()); -} - -bool -ChannelEndPoint::validateSpec() { - isTCP_ = getTCPHostAndPort(); - isUnix_ = getUnixPath(); - return ( getPort() || isUnix_ || isTCP_ ); -} - -ChannelEndPoint &ChannelEndPoint::operator=(const ChannelEndPoint &other) { - char *old; - defaultTCPPort_ = other.defaultTCPPort_; - defaultTCPInterface_ = other.defaultTCPInterface_; - old = defaultUnixPath_; - defaultUnixPath_ = (other.defaultUnixPath_ ? strdup(other.defaultUnixPath_) : NULL); - free(old); - old = spec_; - spec_ = (other.spec_ ? strdup(other.spec_) : NULL); - free(old); - isUnix_ = getUnixPath(); - isTCP_ = getTCPHostAndPort(); - return *this; -} - -std::ostream& operator<<(std::ostream& os, const ChannelEndPoint& endPoint) { - if (endPoint.enabled()) { - char* endPointSpec = NULL; - if (endPoint.getSpec(&endPointSpec)) - { - os << endPointSpec; - free(endPointSpec); - } - else - os << "(invalid)"; - } - else - { - os << "(disabled)"; - } - return os; -} diff --git a/nxcomp/ChannelEndPoint.h b/nxcomp/ChannelEndPoint.h deleted file mode 100644 index 4c0c728f3..000000000 --- a/nxcomp/ChannelEndPoint.h +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ChannelEndPoint_H -#define ChannelEndPoint_H - -#include -#include - -class ChannelEndPoint -{ - private: - long defaultTCPPort_; - int defaultTCPInterface_; // 0=localhost, otherwise IP of public interface. - char *defaultUnixPath_; - char *spec_; - bool isUnix_; - bool isTCP_; - - bool getPort(long *port = NULL) const; - - public: - ChannelEndPoint(const char *spec = NULL); - ~ChannelEndPoint(); - ChannelEndPoint &operator=(const ChannelEndPoint &other); - - bool enabled() const; - bool disabled() { return !enabled(); } - void disable(); - void setSpec(const char *spec); - void setSpec(long port); - void setSpec(const char *hostName, long port); - bool getSpec(char **socketUri) const; - void setDefaultTCPPort(long port); - void setDefaultTCPInterface(int publicInterface); - void setDefaultUnixPath(char *path); - - bool getUnixPath(char **path = NULL) const; - bool isUnixSocket() const; - bool getTCPHostAndPort(char **hostname = NULL, long *port = NULL) const; - long getTCPPort() const; - bool isTCPSocket() const; - - bool validateSpec(); -}; - -std::ostream& operator<<(std::ostream& os, const ChannelEndPoint& endPoint); - -#endif diff --git a/nxcomp/ChannelStore.h b/nxcomp/ChannelStore.h deleted file mode 100644 index 53bb60f73..000000000 --- a/nxcomp/ChannelStore.h +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ChannelStore_H -#define ChannelStore_H - -// -// One message store for each opcode. -// - -#define CHANNEL_STORE_OPCODE_LIMIT 256 - -// -// One split store for each resource. -// - -#define CHANNEL_STORE_RESOURCE_LIMIT 256 - -class ChannelStore -{ - public: - - ChannelStore() - { - } - - virtual ~ChannelStore() - { - } -}; - -#endif /* ChannelStore_H */ diff --git a/nxcomp/CharCache.cpp b/nxcomp/CharCache.cpp deleted file mode 100644 index 88e66e3da..000000000 --- a/nxcomp/CharCache.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "CharCache.h" - -int CharCache::lookup(unsigned char value, unsigned int &index) -{ - for (unsigned int i = 0; i < length_; i++) - if (value == buffer_[i]) - { - index = i; - if (i) - { - unsigned int target = (i >> 1); - do - { - buffer_[i] = buffer_[i - 1]; - i--; - } - while (i > target); - buffer_[target] = value; - } - return 1; - } - insert(value); - return 0; -} - -void CharCache::insert(unsigned char value) -{ - unsigned int insertionPoint = 0; - if (2 >= length_) - insertionPoint = length_; - else - insertionPoint = 2; - unsigned int start; - if (length_ >= 7) - start = 7 - 1; - else - { - start = length_; - length_++; - } - for (unsigned int k = start; k > insertionPoint; k--) - buffer_[k] = buffer_[k - 1]; - buffer_[insertionPoint] = value; -} diff --git a/nxcomp/CharCache.h b/nxcomp/CharCache.h deleted file mode 100644 index b8891d2df..000000000 --- a/nxcomp/CharCache.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef CharCache_H -#define CharCache_H - -// -// CharCache is a counterpart of IntCache that is -// optimized for use in compressing text composed -// of 8-bit characters. -// - -class CharCache -{ - public: - - CharCache() : length_(0) - { - } - - ~CharCache() - { - } - - unsigned int getSize() const - { - return (unsigned int) length_; - } - - int lookup(unsigned char value, unsigned int &index); - - // - // This can be inlined as it is only - // called by decodeCachedValue(). - // - - unsigned int get(unsigned int index) - { - unsigned char result = buffer_[index]; - - if (index != 0) - { - unsigned int i = index; - unsigned int target = (i >> 1); - - do - { - buffer_[i] = buffer_[i - 1]; - - i--; - } - while (i > target); - - buffer_[target] = result; - } - - return (unsigned int) result; - } - - void insert(unsigned char value); - - private: - - unsigned char length_; - - unsigned char buffer_[7]; -}; - -#endif /* CharCache_H */ diff --git a/nxcomp/Children.cpp b/nxcomp/Children.cpp deleted file mode 100644 index 265ba4e37..000000000 --- a/nxcomp/Children.cpp +++ /dev/null @@ -1,1055 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include - -#include "NX.h" - -#include "Misc.h" - -#include "Types.h" -#include "Timestamp.h" - -#include "Control.h" -#include "Statistics.h" -#include "Proxy.h" - -#include "Keeper.h" -#include "Fork.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#define DISPLAY_LENGTH_LIMIT 256 -#define DEFAULT_STRING_LIMIT 512 - -// -// These are from the main loop. -// - -extern Keeper *keeper; - -extern int (*handler)(int); - -extern int useUnixSocket; - -extern int lastDialog; -extern int lastWatchdog; -extern int lastKeeper; - -extern void CleanupListeners(); -extern void CleanupSockets(); -extern void CleanupAgent(); -extern void CleanupGlobal(); - -extern void InstallSignals(); - -extern char *GetClientPath(); - -extern int CheckParent(const char *name, const char *type, - int parent); - -#ifdef __sun -extern char **environ; -#endif - -// -// Close all the unused descriptors and -// install any signal handler that might -// have been disabled in the main process. -// - -static void SystemCleanup(const char *name); - -// -// Release all objects allocated in the -// heap. - -static void MemoryCleanup(const char *name); - -// -// Remove 'name' from the environment. -// - -static int UnsetEnv(const char *name); - -static int NXTransKeeperHandler(int signal); -static void NXTransKeeperCheck(); - - -// -// Start a nxclient process in dialog mode. -// - -int NXTransDialog(const char *caption, const char *message, - const char *window, const char *type, int local, - const char* display) -{ - // - // Be sure log file is valid. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - int pid; - - #ifdef TEST - *logofs << "NXTransDialog: Going to fork with NX pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - pid = Fork(); - - if (pid != 0) - { - if (pid < 0) - { - #ifdef TEST - *logofs << "NXTransDialog: WARNING! Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - #ifdef TEST - else - { - *logofs << "NXTransDialog: Created NX dialog process " - << "with pid '" << pid << "'.\n" - << logofs_flush; - } - #endif - - return pid; - } - - #ifdef TEST - *logofs << "NXTransDialog: Executing child with pid '" - << getpid() << "' and parent '" << getppid() - << "'.\n" << logofs_flush; - #endif - - SystemCleanup("NXTransDialog"); - - // - // Copy the client command before - // freeing up the control class. - // - - char command[DEFAULT_STRING_LIMIT]; - - if (control != NULL) - { - strcpy(command, control -> ClientPath); - } - else - { - char *path = GetClientPath(); - - strcpy(command, path); - - delete [] path; - } - - // - // Get rid of the unused resources. - // - - MemoryCleanup("NXTransDialog"); - - #ifdef TEST - *logofs << "NXTransDialog: Running external NX dialog with caption '" - << caption << "' message '" << message << "' type '" - << type << "' local '" << local << "' display '" - << display << "'.\n" - << logofs_flush; - #endif - - int pulldown = (strcmp(type, "pulldown") == 0); - - char parent[DEFAULT_STRING_LIMIT]; - - snprintf(parent, DEFAULT_STRING_LIMIT, "%d", getppid()); - - parent[DEFAULT_STRING_LIMIT - 1] = '\0'; - - UnsetEnv("LD_LIBRARY_PATH"); - - for (int i = 0; i < 2; i++) - { - if (local != 0) - { - if (pulldown) - { - execlp(command, command, "--dialog", type, "--caption", caption, - "--window", window, "--local", "--parent", parent, - "--display", display, NULL); - } - else - { - execlp(command, command, "--dialog", type, "--caption", caption, - "--message", message, "--local", "--parent", parent, - "--display", display, NULL); - } - } - else - { - if (pulldown) - { - execlp(command, command, "--dialog", type, "--caption", caption, - "--window", window, "--parent", parent, - "--display", display, NULL); - } - else - { - execlp(command, command, "--dialog", type, "--caption", caption, - "--message", message, "--parent", parent, - "--display", display, NULL); - } - } - - #ifdef WARNING - *logofs << "NXTransDialog: WARNING! Couldn't start '" - << command << "'. " << "Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Couldn't start '" << command - << "'. Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - // - // Retry by looking for the default name - // in the default NX path. - // - - if (i == 0) - { - - strcpy(command, "nxclient"); - - char newPath[DEFAULT_STRING_LIMIT]; - - strcpy(newPath, "/usr/NX/bin:/opt/NX/bin:/usr/local/NX/bin:"); - - #ifdef __APPLE__ - - strcat(newPath, "/Applications/NX Client for OSX.app/Contents/MacOS:"); - - #endif - - #ifdef __CYGWIN32__ - - strcat(newPath, ".:"); - - #endif - - int newLength = strlen(newPath); - - char *oldPath = getenv("PATH"); - - strncpy(newPath + newLength, oldPath, DEFAULT_STRING_LIMIT - newLength - 1); - - newPath[DEFAULT_STRING_LIMIT - 1] = '\0'; - - #ifdef WARNING - *logofs << "NXTransDialog: WARNING! Trying with path '" - << newPath << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Trying with path '" << newPath - << "'.\n"; - - // - // Solaris doesn't seem to have - // function setenv(). - // - - #ifdef __sun - - char newEnv[DEFAULT_STRING_LIMIT + 5]; - - sprintf(newEnv,"PATH=%s", newPath); - - putenv(newEnv); - - #else - - setenv("PATH", newPath, 1); - - #endif - - } - } - - // - // Hopefully useless. - // - - exit(0); -} - -// -// Start a nxclient process in dialog mode. -// - -int NXTransClient(const char* display) -{ - // - // Be sure log file is valid. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - int pid; - - #ifdef TEST - *logofs << "NXTransClient: Going to fork with NX pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - pid = Fork(); - - if (pid != 0) - { - if (pid < 0) - { - #ifdef TEST - *logofs << "NXTransClient: WARNING! Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - #ifdef TEST - else - { - *logofs << "NXTransClient: Created NX client process " - << "with pid '" << pid << "'.\n" - << logofs_flush; - } - #endif - - return pid; - } - - #ifdef TEST - *logofs << "NXTransClient: Executing child with pid '" - << getpid() << "' and parent '" << getppid() - << "'.\n" << logofs_flush; - #endif - - SystemCleanup("NXTransClient"); - - // - // Copy the client command before - // freeing up the control class. - // - - char command[DEFAULT_STRING_LIMIT]; - - if (control != NULL) - { - strcpy(command, control -> ClientPath); - } - else - { - char *path = GetClientPath(); - - strcpy(command, path); - - delete [] path; - } - - // - // Get rid of unused resources. - // - - MemoryCleanup("NXTransClient"); - - #ifdef TEST - *logofs << "NXTransClient: Running external NX client with display '" - << display << "'.\n" << logofs_flush; - #endif - - // - // Provide the display in the environment. - // - - char newDisplay[DISPLAY_LENGTH_LIMIT]; - - #ifdef __sun - - snprintf(newDisplay, DISPLAY_LENGTH_LIMIT - 1, "DISPLAY=%s", display); - - newDisplay[DISPLAY_LENGTH_LIMIT - 1] = '\0'; - - putenv(newDisplay); - - #else - - strncpy(newDisplay, display, DISPLAY_LENGTH_LIMIT - 1); - - newDisplay[DISPLAY_LENGTH_LIMIT - 1] = '\0'; - - setenv("DISPLAY", newDisplay, 1); - - #endif - - UnsetEnv("LD_LIBRARY_PATH"); - - for (int i = 0; i < 2; i++) - { - execlp(command, command, NULL); - - #ifdef WARNING - *logofs << "NXTransClient: WARNING! Couldn't start '" - << command << "'. Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Couldn't start '" << command - << "'. Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - // - // Retry by looking for the default name - // in the default NX path. - // - - if (i == 0) - { - - strcpy(command, "nxclient"); - - char newPath[DEFAULT_STRING_LIMIT]; - - strcpy(newPath, "/usr/NX/bin:/opt/NX/bin:/usr/local/NX/bin:"); - - #ifdef __APPLE__ - - strcat(newPath, "/Applications/NX Client for OSX.app/Contents/MacOS:"); - - #endif - - #ifdef __CYGWIN32__ - - strcat(newPath, ".:"); - - #endif - - int newLength = strlen(newPath); - - char *oldPath = getenv("PATH"); - - strncpy(newPath + newLength, oldPath, DEFAULT_STRING_LIMIT - newLength - 1); - - newPath[DEFAULT_STRING_LIMIT - 1] = '\0'; - - #ifdef WARNING - *logofs << "NXTransClient: WARNING! Trying with path '" - << newPath << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Trying with path '" << newPath - << "'.\n"; - - // - // Solaris doesn't seem to have - // function setenv(). - // - - #ifdef __sun - - char newEnv[DEFAULT_STRING_LIMIT + 5]; - - sprintf(newEnv,"PATH=%s", newPath); - - putenv(newEnv); - - #else - - setenv("PATH", newPath, 1); - - #endif - } - - } - // - // Hopefully useless. - // - - exit(0); -} - -// -// Wait until the timeout is expired. -// The timeout is expressed in milli- -// seconds. -// - -int NXTransWatchdog(int timeout) -{ - // - // Be sure log file is valid. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - int pid; - - #ifdef TEST - *logofs << "NXTransWatchdog: Going to fork with NX pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - pid = Fork(); - - if (pid != 0) - { - if (pid < 0) - { - #ifdef TEST - *logofs << "NXTransWatchdog: WARNING! Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - #ifdef TEST - else - { - *logofs << "NXTransWatchdog: Created NX watchdog process " - << "with pid '" << pid << "'.\n" << logofs_flush; - } - #endif - - return pid; - } - - int parent = getppid(); - - #ifdef TEST - *logofs << "NXTransWatchdog: Executing child with pid '" - << getpid() << "' and parent '" << parent - << "'.\n" << logofs_flush; - #endif - - SystemCleanup("NXTransWatchdog"); - - // - // Get rid of unused resources. - // - - MemoryCleanup("NXTransWatchdog"); - - // - // Run until the timeout is expired - // or forever, if no timeout is - // provided. - // - - T_timestamp startTs = getTimestamp(); - - int diffTs = 0; - - for (;;) - { - // - // Complain if the parent is dead. - // - - if (CheckParent("NXTransWatchdog", "watchdog", parent) == 0) - { - #ifdef TEST - *logofs << "NXTransWatchdog: Exiting with no parent " - << "running.\n" << logofs_flush; - #endif - - HandleCleanup(); - } - - if (timeout > 0) - { - if (diffTs >= timeout) - { - #ifdef TEST - *logofs << "NXTransWatchdog: Timeout of " << timeout - << " Ms raised in watchdog.\n" << logofs_flush; - #endif - - // - // We will just exit. Our parent should be - // monitoring us and detect that the process - // is gone. - // - - HandleCleanup(); - } - } - - if (timeout > 0) - { - #ifdef TEST - *logofs << "NXTransWatchdog: Waiting for the timeout " - << "with " << timeout - diffTs << " Ms to run.\n" - << logofs_flush; - #endif - - usleep((timeout - diffTs) * 1000); - - diffTs = diffTimestamp(startTs, getNewTimestamp()); - } - else - { - #ifdef TEST - *logofs << "NXTransWatchdog: Waiting for a signal.\n" - << logofs_flush; - #endif - - sleep(10); - } - } - - // - // Hopefully useless. - // - - exit(0); -} - -int NXTransKeeperHandler(int signal) -{ - if (keeper != NULL) - { - switch (signal) - { - case SIGTERM: - case SIGINT: - case SIGHUP: - { - #ifdef TEST - *logofs << "NXTransKeeperHandler: Requesting giveup " - << "because of signal " << signal << " ,'" - << DumpSignal(signal) << "'.\n" - << logofs_flush; - #endif - - keeper -> setSignal(signal); - - return 0; - } - } - } - - return 1; -} - -void NXTransKeeperCheck() -{ - if (CheckParent("NXTransKeeper", "keeper", - keeper -> getParent()) == 0 || keeper -> getSignal() != 0) - { - #ifdef TEST - *logofs << "NXTransKeeperCheck: Exiting because of signal " - << "or no parent running.\n" << logofs_flush; - #endif - - HandleCleanup(); - } -} - -int NXTransKeeper(int caches, int images, const char *root) -{ - // - // Be sure log file is valid. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - if (caches == 0 && images == 0) - { - #ifdef TEST - *logofs << "NXTransKeeper: No NX cache house-keeping needed.\n" - << logofs_flush; - #endif - - return 0; - } - - int pid; - - #ifdef TEST - *logofs << "NXTransKeeper: Going to fork with NX pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - pid = Fork(); - - if (pid != 0) - { - if (pid < 0) - { - #ifdef TEST - *logofs << "NXTransKeeper: WARNING! Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - #ifdef TEST - else - { - *logofs << "NXTransKeeper: Created NX keeper process " - << "with pid '" << pid << "'.\n" - << logofs_flush; - } - #endif - - return pid; - } - - int parent = getppid(); - - #ifdef TEST - *logofs << "NXTransKeeper: Executing child with pid '" - << getpid() << "' and parent '" << parent - << "'.\n" << logofs_flush; - #endif - - SystemCleanup("NXTransKeeper"); - - #ifdef TEST - *logofs << "NXTransKeeper: Going to run with caches " << caches - << " images " << images << " and root " << root - << " at " << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - // - // Create the house-keeper class. - // - - int timeout = control -> KeeperTimeout; - - keeper = new Keeper(caches, images, root, 100, parent); - - handler = NXTransKeeperHandler; - - if (keeper == NULL) - { - #ifdef PANIC - *logofs << "NXTransKeeper: PANIC! Failed to create the keeper object.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed to create the keeper object.\n"; - - HandleCleanup(); - } - - // - // Get rid of unused resources. Root path - // must be copied in keeper's constructor - // before control is deleted. - // - - MemoryCleanup("NXTransKeeper"); - - // - // Decrease the priority of this process. - // - // The following applies to Cygwin: "Cygwin processes can be - // set to IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, HIGH_- - // PRIORITY_CLASS, or REALTIME_PRIORITY_CLASS with the nice - // call. If you pass a positive number to nice(), then the - // priority level will decrease by one (within the above list - // of priorities). A negative number would make it increase - // by one. It is not possible to change it by more than one - // at a time without making repeated calls". - // - - if (nice(5) < 0 && errno != 0) - { - #ifdef WARNING - *logofs << "NXTransKeeper: WARNING! Failed to renice process to +5. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Failed to renice process to +5. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - - // - // Delay a bit the first run to give - // a boost to the session startup. - // - - #ifdef TEST - *logofs << "NXTransKeeper: Going to sleep for " - << timeout / 20 << " Ms.\n" << logofs_flush; - #endif - - usleep(timeout / 20 * 1000); - - NXTransKeeperCheck(); - - // - // The house keeping of the persistent - // caches is performed only once. - // - - if (caches != 0) - { - #ifdef TEST - *logofs << "NXTransKeeper: Going to cleanup the NX cache " - << "directories at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - keeper -> cleanupCaches(); - - #ifdef TEST - *logofs << "NXTransKeeper: Completed cleanup of NX cache " - << "directories at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - } - #ifdef TEST - else - { - *logofs << "NXTransKeeper: Nothing to do for the " - << "persistent caches.\n" << logofs_flush; - } - #endif - - if (images == 0) - { - #ifdef TEST - *logofs << "NXTransKeeper: Nothing to do for the " - << "persistent images.\n" << logofs_flush; - #endif - - HandleCleanup(); - } - - // - // Take care of the persisten image cache. - // Run a number of iterations and then exit, - // so we can keep the memory consumption - // low. The parent will check our exit code - // and will eventually restart us. - // - - for (int iterations = 0; iterations < 100; iterations++) - { - #ifdef TEST - *logofs << "NXTransKeeper: Running iteration " << iterations - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - NXTransKeeperCheck(); - - #ifdef TEST - *logofs << "NXTransKeeper: Going to cleanup the NX images " - << "directories at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - if (keeper -> cleanupImages() < 0) - { - #ifdef TEST - *logofs << "NXTransKeeper: Exiting because of error " - << "handling the image cache.\n" << logofs_flush; - #endif - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "NXTransKeeper: Completed cleanup of NX images " - << "directories at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - NXTransKeeperCheck(); - - #ifdef TEST - *logofs << "NXTransKeeper: Going to sleep for " << timeout - << " Ms.\n" << logofs_flush; - #endif - - usleep(timeout * 1000); - } - - HandleCleanup(2); - - // - // Hopefully useless. - // - - exit(0); -} - -void SystemCleanup(const char *name) -{ - #ifdef TEST - *logofs << name << ": Performing system cleanup in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - // - // Reinstall signals that might - // have been restored by agents. - // - - InstallSignals(); -} - -void MemoryCleanup(const char *name) -{ - #ifdef TEST - *logofs << name << ": Performing memory cleanup in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - DisableSignals(); - - // - // Prevent deletion of unix socket - // and lock file. - // - - useUnixSocket = 0; - - // - // Don't let cleanup kill other - // children. - // - - lastDialog = 0; - lastWatchdog = 0; - lastKeeper = 0; - - CleanupListeners(); - - CleanupSockets(); - - CleanupGlobal(); - - EnableSignals(); -} - -int UnsetEnv(const char *name) -{ - int result; - - #ifdef __sun - - char **pEnv = environ; - - int nameLen = strlen(name) + 1; - - char *varName = new char[nameLen + 1]; - - strcpy(varName, name); - - strcat(varName, "="); - - pEnv = environ; - - while (*pEnv != NULL) - { - if (!strncmp(varName, *pEnv, nameLen)) - { - break; - } - - *pEnv++; - } - - while (*pEnv != NULL) - { - *pEnv = *(pEnv + 1); - - pEnv++; - } - - result = 0; - - #else - - #ifdef __APPLE__ - - unsetenv(name); - result = 0; - - #else - - result = unsetenv(name); - - #endif - - #endif - - return result; -} diff --git a/nxcomp/ClearArea.cpp b/nxcomp/ClearArea.cpp deleted file mode 100644 index b76e750a4..000000000 --- a/nxcomp/ClearArea.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ClearArea.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int ClearAreaStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ClearAreaMessage *clearArea = (ClearAreaMessage *) message; - - // - // Here is the fingerprint. - // - - clearArea -> exposures = *(buffer + 1); - - clearArea -> window = GetULONG(buffer + 4, bigEndian); - - clearArea -> x = GetUINT(buffer + 8, bigEndian); - clearArea -> y = GetUINT(buffer + 10, bigEndian); - clearArea -> width = GetUINT(buffer + 12, bigEndian); - clearArea -> height = GetUINT(buffer + 14, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int ClearAreaStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ClearAreaMessage *clearArea = (ClearAreaMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = clearArea -> exposures; - - PutULONG(clearArea -> window, buffer + 4, bigEndian); - - PutUINT(clearArea -> x, buffer + 8, bigEndian); - PutUINT(clearArea -> y, buffer + 10, bigEndian); - PutUINT(clearArea -> width, buffer + 12, bigEndian); - PutUINT(clearArea -> height, buffer + 14, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void ClearAreaStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - ClearAreaMessage *clearArea = (ClearAreaMessage *) message; - - *logofs << name() << ": Identity exposures " << (unsigned int) clearArea -> exposures - << ", window " << clearArea -> window << ", x " << clearArea -> x - << ", y " << clearArea -> y << ", width " << clearArea -> width - << ", height " << clearArea -> height << ", size " << clearArea -> size_ - << ".\n"; - - #endif -} - -void ClearAreaStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 1, 1); - md5_append(md5_state_, buffer + 4, 4); - md5_append(md5_state_, buffer + 8, 2); - md5_append(md5_state_, buffer + 10, 2); - md5_append(md5_state_, buffer + 12, 2); - md5_append(md5_state_, buffer + 14, 2); -} diff --git a/nxcomp/ClearArea.h b/nxcomp/ClearArea.h deleted file mode 100644 index 8067edffd..000000000 --- a/nxcomp/ClearArea.h +++ /dev/null @@ -1,182 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ClearArea_H -#define ClearArea_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define CLEARAREA_ENABLE_CACHE 1 -#define CLEARAREA_ENABLE_DATA 0 -#define CLEARAREA_ENABLE_SPLIT 0 -#define CLEARAREA_ENABLE_COMPRESS 0 - -#define CLEARAREA_DATA_LIMIT 0 -#define CLEARAREA_DATA_OFFSET 16 - -#define CLEARAREA_CACHE_SLOTS 3000 -#define CLEARAREA_CACHE_THRESHOLD 5 -#define CLEARAREA_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class ClearAreaMessage : public Message -{ - friend class ClearAreaStore; - - public: - - ClearAreaMessage() - { - } - - ~ClearAreaMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char exposures; - unsigned int window; - unsigned short x; - unsigned short y; - unsigned short width; - unsigned short height; -}; - -class ClearAreaStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - ClearAreaStore() : MessageStore() - { - enableCache = CLEARAREA_ENABLE_CACHE; - enableData = CLEARAREA_ENABLE_DATA; - enableSplit = CLEARAREA_ENABLE_SPLIT; - enableCompress = CLEARAREA_ENABLE_COMPRESS; - - dataLimit = CLEARAREA_DATA_LIMIT; - dataOffset = CLEARAREA_DATA_OFFSET; - - cacheSlots = CLEARAREA_CACHE_SLOTS; - cacheThreshold = CLEARAREA_CACHE_THRESHOLD; - cacheLowerThreshold = CLEARAREA_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~ClearAreaStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "ClearArea"; - } - - virtual unsigned char opcode() const - { - return X_ClearArea; - } - - virtual unsigned int storage() const - { - return sizeof(ClearAreaMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new ClearAreaMessage(); - } - - virtual Message *create(const Message &message) const - { - return new ClearAreaMessage((const ClearAreaMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (ClearAreaMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* ClearArea_H */ diff --git a/nxcomp/ClientCache.cpp b/nxcomp/ClientCache.cpp deleted file mode 100644 index b6c04dd0b..000000000 --- a/nxcomp/ClientCache.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ClientCache.h" - -ClientCache::ClientCache() : - - freeGCCache(16), freeDrawableCache(16), freeWindowCache(16), - - cursorCache(16), colormapCache(16), visualCache(16), lastFont(0), - - changePropertyPropertyCache(16), changePropertyTypeCache(16), - changePropertyData32Cache(16), - - configureWindowBitmaskCache(4), - - convertSelectionRequestorCache(16), - convertSelectionLastTimestamp(0), - - copyPlaneBitPlaneCache(8), - - createGCBitmaskCache(8), - - createPixmapIdCache(16), createPixmapLastId(0), - createPixmapXCache(8), createPixmapYCache(8), - - createWindowBitmaskCache(8), - - fillPolyNumPointsCache(8), fillPolyIndex(0), - - getSelectionOwnerSelectionCache(8), - - grabButtonEventMaskCache(8), grabButtonConfineCache(8), - grabButtonModifierCache(8), - - grabKeyboardLastTimestamp(0), - - imageTextLengthCache(8), - imageTextLastX(0), imageTextLastY(0), - imageTextCacheX(8), imageTextCacheY(8), - - polySegmentCacheX(8), polySegmentCacheY(8), polySegmentCacheIndex(0), - - polyTextLastX(0), polyTextLastY(0), polyTextCacheX(8), - polyTextCacheY(8), polyTextFontCache(8), - - putImageWidthCache(8), putImageHeightCache(8), putImageLastX(0), - putImageLastY(0), putImageXCache(8), putImageYCache(8), - - getImagePlaneMaskCache(8), - - queryColorsLastPixel(0), - - setClipRectanglesXCache(8), setClipRectanglesYCache(8), - - setDashesLengthCache(8), setDashesOffsetCache(8), - - setSelectionOwnerCache(8), setSelectionOwnerTimestampCache(8), - - translateCoordsSrcCache(8), translateCoordsDstCache(8), - translateCoordsXCache(8), translateCoordsYCache(8), - - sendEventMaskCache(16), sendEventLastSequence(0), - sendEventIntDataCache(16), - - putPackedImageSrcLengthCache(16), putPackedImageDstLengthCache(16), - - // - // RenderExtension requests. - // - - renderFreePictureCache(16), - - renderGlyphSetCache(16), - renderFreeGlyphSetCache(16), - - renderIdCache(8), - - renderLengthCache(16), renderFormatCache(16), - renderValueMaskCache(8), renderNumGlyphsCache(8), - - renderXCache(16), renderYCache(16), - renderLastX(0), renderLastY(0), - - renderWidthCache(16), renderHeightCache(16), - - renderLastId(0), - - renderGlyphXCache(16), renderGlyphYCache(16), - renderGlyphX(0), renderGlyphY(0), - - renderLastCompositeGlyphsData(0), - - setCacheParametersCache(8), - - lastIdCache(16), lastId(0) - -{ - unsigned int i; - - for (i = 0; i < 3; i++) - { - allocColorRGBCache[i] = new IntCache(8); - - convertSelectionAtomCache[i] = new IntCache(8); - } - - for (i = 0; i < 4; i++) - { - clearAreaGeomCache[i] = new IntCache(8); - } - - for (i = 0; i < 7; i++) - { - configureWindowAttrCache[i] = new IntCache(8); - } - - for (i = 0; i < 6; i++) - { - copyAreaGeomCache[i] = new IntCache(8); - copyPlaneGeomCache[i] = new IntCache(8); - } - - for (i = 0; i < 23; i++) - { - if (CREATEGC_FIELD_WIDTH[i] > 16) - { - createGCAttrCache[i] = new IntCache(16); - } - else - { - createGCAttrCache[i] = new IntCache(CREATEGC_FIELD_WIDTH[i]); - } - } - - for (i = 0; i < 6; i++) - { - createWindowGeomCache[i] = new IntCache(8); - } - - for (i = 0; i < 15; i++) - { - createWindowAttrCache[i] = new IntCache(8); - } - - for (i = 0; i < 10; i++) - { - fillPolyXRelCache[i] = new IntCache(8); - fillPolyXAbsCache[i] = new IntCache(8); - fillPolyYRelCache[i] = new IntCache(8); - fillPolyYAbsCache[i] = new IntCache(8); - } - - for (i = 0; i < 8; i++) - { - fillPolyRecentX[i] = 0; - fillPolyRecentY[i] = 0; - } - - for (i = 0; i < 4; i++) - { - polyFillRectangleCacheX[i] = new IntCache(8); - polyFillRectangleCacheY[i] = new IntCache(8); - polyFillRectangleCacheWidth[i] = new IntCache(8); - polyFillRectangleCacheHeight[i] = new IntCache(8); - } - - for (i = 0; i < 2; i++) - { - polyLineCacheX[i] = new IntCache(8); - polyLineCacheY[i] = new IntCache(8); - } - - for (i = 0; i < 2; i++) - { - polyPointCacheX[i] = new IntCache(8); - polyPointCacheY[i] = new IntCache(8); - } - - for (i = 0; i < 4; i++) - { - polyRectangleGeomCache[i] = new IntCache(8); - } - - for (i = 0; i < 2; i++) - { - polySegmentLastX[i] = 0; - polySegmentLastY[i] = 0; - } - - for (i = 0; i < 4; i++) - { - setClipRectanglesGeomCache[i] = new IntCache(8); - } - - for (i = 0; i < 2; i++) - { - polyFillArcCacheX[i] = new IntCache(8); - polyFillArcCacheY[i] = new IntCache(8); - polyFillArcCacheWidth[i] = new IntCache(8); - polyFillArcCacheHeight[i] = new IntCache(8); - polyFillArcCacheAngle1[i] = new IntCache(8); - polyFillArcCacheAngle2[i] = new IntCache(8); - } - - for (i = 0; i < 2; i++) - { - polyArcCacheX[i] = new IntCache(8); - polyArcCacheY[i] = new IntCache(8); - polyArcCacheWidth[i] = new IntCache(8); - polyArcCacheHeight[i] = new IntCache(8); - polyArcCacheAngle1[i] = new IntCache(8); - polyArcCacheAngle2[i] = new IntCache(8); - } - - for (i = 0; i < 8; i++) - { - shapeDataCache[i] = new IntCache(8); - } - - for (i = 0; i < 8; i++) - { - genericRequestDataCache[i] = new IntCache(8); - } - - for (i = 0; i < 16; i++) - { - renderDataCache[i] = new IntCache(16); - } - - for (i = 0; i < 16; i++) - { - renderCompositeGlyphsDataCache[i] = new IntCache(16); - } - - for (i = 0; i < 3; i++) - { - renderCompositeDataCache[i] = new IntCache(16); - } -} - - -ClientCache::~ClientCache() -{ - unsigned int i; - - for (i = 0; i < 3; i++) - { - delete allocColorRGBCache[i]; - delete convertSelectionAtomCache[i]; - } - - for (i = 0; i < 4; i++) - { - delete clearAreaGeomCache[i]; - } - - for (i = 0; i < 7; i++) - { - delete configureWindowAttrCache[i]; - } - - for (i = 0; i < 6; i++) - { - delete copyAreaGeomCache[i]; - delete copyPlaneGeomCache[i]; - } - - for (i = 0; i < 23; i++) - { - delete createGCAttrCache[i]; - } - - for (i = 0; i < 6; i++) - { - delete createWindowGeomCache[i]; - } - - for (i = 0; i < 15; i++) - { - delete createWindowAttrCache[i]; - } - - for (i = 0; i < 10; i++) - { - delete fillPolyXRelCache[i]; - delete fillPolyXAbsCache[i]; - delete fillPolyYRelCache[i]; - delete fillPolyYAbsCache[i]; - } - - for (i = 0; i < 4; i++) - { - delete polyFillRectangleCacheX[i]; - delete polyFillRectangleCacheY[i]; - delete polyFillRectangleCacheWidth[i]; - delete polyFillRectangleCacheHeight[i]; - } - - for (i = 0; i < 2; i++) - { - delete polyLineCacheX[i]; - delete polyLineCacheY[i]; - } - - for (i = 0; i < 2; i++) - { - delete polyPointCacheX[i]; - delete polyPointCacheY[i]; - } - - for (i = 0; i < 4; i++) - { - delete polyRectangleGeomCache[i]; - } - - for (i = 0; i < 4; i++) - { - delete setClipRectanglesGeomCache[i]; - } - - for (i = 0; i < 2; i++) - { - delete polyFillArcCacheX[i]; - delete polyFillArcCacheY[i]; - delete polyFillArcCacheWidth[i]; - delete polyFillArcCacheHeight[i]; - delete polyFillArcCacheAngle1[i]; - delete polyFillArcCacheAngle2[i]; - } - - for (i = 0; i < 2; i++) - { - delete polyArcCacheX[i]; - delete polyArcCacheY[i]; - delete polyArcCacheWidth[i]; - delete polyArcCacheHeight[i]; - delete polyArcCacheAngle1[i]; - delete polyArcCacheAngle2[i]; - } - - for (i = 0; i < 8; i++) - { - delete shapeDataCache[i]; - } - - for (i = 0; i < 8; i++) - { - delete genericRequestDataCache[i]; - } - - for (i = 0; i < 16; i++) - { - delete renderDataCache[i]; - } - - for (i = 0; i < 16; i++) - { - delete renderCompositeGlyphsDataCache[i]; - } - - for (i = 0; i < 3; i++) - { - delete renderCompositeDataCache[i]; - } -} diff --git a/nxcomp/ClientCache.h b/nxcomp/ClientCache.h deleted file mode 100644 index ed3361097..000000000 --- a/nxcomp/ClientCache.h +++ /dev/null @@ -1,417 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ClientCache_H -#define ClientCache_H - -#include "Misc.h" - -#include "IntCache.h" -#include "CharCache.h" -#include "OpcodeCache.h" -#include "XidCache.h" -#include "FreeCache.h" - -#include "ChannelCache.h" - -class ClientCache : public ChannelCache -{ - public: - - ClientCache(); - - ~ClientCache(); - - // - // Opcode prediction caches. - // - - OpcodeCache opcodeCache; - - // - // GC and drawables caches. - // - - XidCache gcCache; - FreeCache freeGCCache; - - XidCache drawableCache; - FreeCache freeDrawableCache; - - XidCache windowCache; - FreeCache freeWindowCache; - - // - // General-purpose caches. - // - - IntCache cursorCache; - IntCache colormapCache; - IntCache visualCache; - CharCache depthCache; - CharCache resourceCache; - CharCache methodCache; - - unsigned int lastFont; - - // - // AllocColor request. - // - - IntCache *allocColorRGBCache[3]; - - // - // ChangeProperty request. - // - - CharCache changePropertyFormatCache; - IntCache changePropertyPropertyCache; - IntCache changePropertyTypeCache; - IntCache changePropertyData32Cache; - - // - // ClearArea request. - // - - IntCache *clearAreaGeomCache[4]; - - // - // ConfigureWindow request. - // - - IntCache configureWindowBitmaskCache; - IntCache *configureWindowAttrCache[7]; - - // - // ConvertSelection request. - // - - IntCache convertSelectionRequestorCache; - IntCache* convertSelectionAtomCache[3]; - unsigned int convertSelectionLastTimestamp; - - // - // CopyArea request. - // - - IntCache *copyAreaGeomCache[6]; - - // - // CopyPlane request. - // - - IntCache *copyPlaneGeomCache[6]; - IntCache copyPlaneBitPlaneCache; - - // - // CreateGC request. - // - - IntCache createGCBitmaskCache; - IntCache *createGCAttrCache[23]; - - // - // CreatePixmap request. - // - - IntCache createPixmapIdCache; - unsigned int createPixmapLastId; - IntCache createPixmapXCache; - IntCache createPixmapYCache; - - // - // CreateWindow request. - // - - IntCache *createWindowGeomCache[6]; - IntCache createWindowBitmaskCache; - IntCache *createWindowAttrCache[15]; - - // - // FillPoly request. - // - - IntCache fillPolyNumPointsCache; - IntCache *fillPolyXRelCache[10]; - IntCache *fillPolyXAbsCache[10]; - IntCache *fillPolyYRelCache[10]; - IntCache *fillPolyYAbsCache[10]; - unsigned int fillPolyRecentX[8]; - unsigned int fillPolyRecentY[8]; - unsigned int fillPolyIndex; - - // - // GetSelectionOwner request. - // - - IntCache getSelectionOwnerSelectionCache; - - // - // GrabButton request (also used for GrabPointer). - // - - IntCache grabButtonEventMaskCache; - IntCache grabButtonConfineCache; - CharCache grabButtonButtonCache; - IntCache grabButtonModifierCache; - - // - // GrabKeyboard request. - // - - unsigned int grabKeyboardLastTimestamp; - - // - // ImageText8/16 request. - // - - IntCache imageTextLengthCache; - unsigned int imageTextLastX; - unsigned int imageTextLastY; - IntCache imageTextCacheX; - IntCache imageTextCacheY; - - // - // PolyFillRectangle request. - // - - IntCache *polyFillRectangleCacheX[4]; - IntCache *polyFillRectangleCacheY[4]; - IntCache *polyFillRectangleCacheWidth[4]; - IntCache *polyFillRectangleCacheHeight[4]; - - // - // PolyLine request. - // - - IntCache *polyLineCacheX[2]; - IntCache *polyLineCacheY[2]; - - // - // PolyPoint request. - // - - IntCache *polyPointCacheX[2]; - IntCache *polyPointCacheY[2]; - - // - // PolyRectangle request. - // - - IntCache *polyRectangleGeomCache[4]; - - // - // PolySegment request. - // - - IntCache polySegmentCacheX; - IntCache polySegmentCacheY; - unsigned int polySegmentLastX[2]; - unsigned int polySegmentLastY[2]; - unsigned int polySegmentCacheIndex; - - // - // PolyText8/16 request. - // - - unsigned int polyTextLastX; - unsigned int polyTextLastY; - IntCache polyTextCacheX; - IntCache polyTextCacheY; - IntCache polyTextFontCache; - CharCache polyTextDeltaCache; - - // - // PutImage request. - // - - IntCache putImageWidthCache; - IntCache putImageHeightCache; - unsigned int putImageLastX; - unsigned int putImageLastY; - IntCache putImageXCache; - IntCache putImageYCache; - CharCache putImageLeftPadCache; - - // - // GetImage request. - // - - IntCache getImagePlaneMaskCache; - - // - // QueryColors request. - // - - unsigned int queryColorsLastPixel; - - // - // SetClipRectangles request. - // - - IntCache setClipRectanglesXCache; - IntCache setClipRectanglesYCache; - IntCache *setClipRectanglesGeomCache[4]; - - // - // SetDashes request. - // - - IntCache setDashesLengthCache; - IntCache setDashesOffsetCache; - CharCache setDashesDashCache_[2]; - - // - // SetSelectionOwner request. - // - - IntCache setSelectionOwnerCache; - IntCache setSelectionOwnerTimestampCache; - - // - // TranslateCoords request. - // - - IntCache translateCoordsSrcCache; - IntCache translateCoordsDstCache; - IntCache translateCoordsXCache; - IntCache translateCoordsYCache; - - // - // SendEvent request. - // - - IntCache sendEventMaskCache; - CharCache sendEventCodeCache; - CharCache sendEventByteDataCache; - unsigned int sendEventLastSequence; - IntCache sendEventIntDataCache; - CharCache sendEventEventCache; - - // - // PolyFillArc request. - // - - IntCache *polyFillArcCacheX[2]; - IntCache *polyFillArcCacheY[2]; - IntCache *polyFillArcCacheWidth[2]; - IntCache *polyFillArcCacheHeight[2]; - IntCache *polyFillArcCacheAngle1[2]; - IntCache *polyFillArcCacheAngle2[2]; - - // - // PolyArc request. - // - - IntCache *polyArcCacheX[2]; - IntCache *polyArcCacheY[2]; - IntCache *polyArcCacheWidth[2]; - IntCache *polyArcCacheHeight[2]; - IntCache *polyArcCacheAngle1[2]; - IntCache *polyArcCacheAngle2[2]; - - // - // PutPackedImage request. - // - - IntCache putPackedImageSrcLengthCache; - IntCache putPackedImageDstLengthCache; - - // - // Shape extension requests. - // - - CharCache shapeOpcodeCache; - IntCache *shapeDataCache[8]; - - // - // Generic requests. - // - - CharCache genericRequestOpcodeCache; - IntCache *genericRequestDataCache[8]; - - // - // Render extension requests. - // - - OpcodeCache renderOpcodeCache; - - CharCache renderOpCache; - - XidCache renderSrcPictureCache; - XidCache renderMaskPictureCache; - XidCache renderDstPictureCache; - FreeCache renderFreePictureCache; - - IntCache renderGlyphSetCache; - FreeCache renderFreeGlyphSetCache; - - IntCache renderIdCache; - IntCache renderLengthCache; - IntCache renderFormatCache; - IntCache renderValueMaskCache; - IntCache renderNumGlyphsCache; - - IntCache renderXCache; - IntCache renderYCache; - - unsigned int renderLastX; - unsigned int renderLastY; - - IntCache renderWidthCache; - IntCache renderHeightCache; - - unsigned int renderLastId; - - IntCache *renderDataCache[16]; - - IntCache renderGlyphXCache; - IntCache renderGlyphYCache; - - unsigned int renderGlyphX; - unsigned int renderGlyphY; - - IntCache *renderCompositeGlyphsDataCache[16]; - unsigned int renderLastCompositeGlyphsData; - - IntCache *renderCompositeDataCache[3]; - - // - // SetCacheParameters request. - // - - IntCache setCacheParametersCache; - - // - // Encode new XID values based - // on the last value encoded. - // - - IntCache lastIdCache; - unsigned int lastId; -}; - -#endif /* ClientCache_H */ diff --git a/nxcomp/ClientChannel.cpp b/nxcomp/ClientChannel.cpp deleted file mode 100644 index dbf5f6986..000000000 --- a/nxcomp/ClientChannel.cpp +++ /dev/null @@ -1,7877 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include - -#include -#include - -#include "NXproto.h" -#include "NXrender.h" - -#include "ClientChannel.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "StaticCompressor.h" - -#include "Statistics.h" -#include "Proxy.h" - -#include "PutImage.h" -#include "PutPackedImage.h" - -extern Proxy *proxy; - -// -// Set the verbosity level. You also -// need to define OPCODES in Misc.cpp -// if you want literals instead of -// opcodes' numbers. -// - -#define PANIC -#define WARNING -#undef OPCODES -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Log the important tracepoints related -// to writing packets to the peer proxy. -// - -#undef FLUSH - -// -// Log the operations related to splits. -// - -#undef SPLIT - -// -// Define this to trace the invocations -// of the agent's callbacks. -// - -#undef CALLBACK - -// -// By defining this, a simple procedure is activated at -// startup which just allocates and deallocates plenty -// of cache objects. This is used to help determine the -// current memory requirements. -// - -#undef MEMORY - -// -// Inspects target of common X operations. -// - -#undef TARGETS - -#ifdef TARGETS - -#include -#include - -typedef set < unsigned int, less > T_windows; -typedef set < unsigned int, less > T_pixmaps; -typedef map < unsigned int, unsigned int, less > T_gcontexts; - -T_windows windows; -T_pixmaps pixmaps; -T_gcontexts gcontexts; - -#endif - -// -// Define this to log when a channel -// is created or destroyed. -// - -#undef REFERENCES - -// -// Here are the static members. -// - -#ifdef REFERENCES - -int ClientChannel::references_ = 0; - -#endif - -ClientChannel::ClientChannel(Transport *transport, StaticCompressor *compressor) - - : Channel(transport, compressor), readBuffer_(transport_, this) -{ - // - // Sequence number of the next message - // being encoded or decoded. - // - - clientSequence_ = 0; - serverSequence_ = 0; - - // - // Current sequence known by NX agent. - // - - lastSequence_ = 0; - - // - // This is used to test the synchronous - // flush in the proxy. - // - - lastRequest_ = 0; - - // - // Store information about the images - // being streamed. - // - - splitState_.resource = nothing; - splitState_.pending = 0; - splitState_.commit = 0; - splitState_.mode = split_none; - - // - // Number of outstanding tainted replies. - // - - taintCounter_ = 0; - - #ifdef MEMORY - - *logofs << "ClientChannel: Created 1 ClientCache and 1 ServerCache. " - << "You have 30 seconds to check the allocated size.\n" - << logofs_flush; - - sleep(30); - - ClientCache *clientCacheTestArray[100]; - ServerCache *serverCacheTestArray[100]; - - for (int i = 0; i < 100; i++) - { - clientCacheTestArray[i] = new ClientCache(); - } - - *logofs << "ClientChannel: Created further 100 ClientCache. " - << "You have 30 seconds to check the allocated size.\n" - << logofs_flush; - - sleep(30); - - for (int i = 0; i < 100; i++) - { - serverCacheTestArray[i] = new ServerCache(); - } - - *logofs << "ClientChannel: Created further 100 ServerCache. " - << "You have 30 seconds to check the allocated size.\n" - << logofs_flush; - - sleep(30); - - for (int i = 0; i < 100; i++) - { - delete clientCacheTestArray[i]; - delete serverCacheTestArray[i]; - } - - *logofs << "ClientChannel: Deleted 100 ClientCache and 100 ServerCache. " - << "You have 30 seconds to check the allocated size.\n" - << logofs_flush; - - sleep(30); - - #endif - - #ifdef REFERENCES - *logofs << "ClientChannel: Created new object at " - << this << " for FD#" << fd_ << " out of " - << ++references_ << " allocated channels.\n" - << logofs_flush; - #endif -} - -ClientChannel::~ClientChannel() -{ - #ifdef REFERENCES - *logofs << "ClientChannel: Deleted object at " - << this << " for FD#" << fd_ << " out of " - << --references_ << " allocated channels.\n" - << logofs_flush; - #endif -} - -// -// Beginning of handleRead(). -// - -int ClientChannel::handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, - unsigned int length) -{ - #ifdef TEST - *logofs << "handleRead: Called for FD#" << fd_ - << " with " << encodeBuffer.getLength() - << " bytes already encoded.\n" - << logofs_flush; - #endif - - // - // Pointer to located message and - // its size in bytes. - // - - const unsigned char *inputMessage; - unsigned int inputLength; - - // - // Set when message is found in - // cache. - // - - int hit; - - // - // Check if we can borrow the buffer - // from the caller. - // - - if (message != NULL && length != 0) - { - readBuffer_.readMessage(message, length); - } - else - { - // - // Get the data from the transport. - // - - #if defined(TEST) || defined(INFO) - *logofs << "handleRead: Trying to read from FD#" - << fd_ << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - int result = readBuffer_.readMessage(); - - #ifdef DEBUG - *logofs << "handleRead: Read result on FD#" << fd_ - << " is " << result << ".\n" - << logofs_flush; - #endif - - if (result < 0) - { - // - // Let the proxy close the channel. - // - - return -1; - } - else if (result == 0) - { - #if defined(TEST) || defined(INFO) - - *logofs << "handleRead: PANIC! No data read from FD#" - << fd_ << " while encoding messages.\n" - << logofs_flush; - - HandleCleanup(); - - #endif - - return 0; - } - } - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "handleRead: Encoding messages for FD#" << fd_ - << " with " << readBuffer_.getLength() << " bytes " - << "in the buffer.\n" << logofs_flush; - #endif - - // - // Extract any complete message which - // is available in the buffer. - // - - if (proxy -> handleAsyncSwitch(fd_) < 0) - { - return -1; - } - - while ((inputMessage = readBuffer_.getMessage(inputLength)) != NULL) - { - hit = 0; - - if (firstRequest_) - { - // - // Need to add the length of the first - // request as it was not present in - // previous versions. - // - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeValue(inputLength, 8); - - for (unsigned int i = 0; i < inputLength; i++) - { - encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8); - } - - firstRequest_ = 0; - - #if defined(TEST) || defined(OPCODES) - - int bits = encodeBuffer.diffBits(); - - *logofs << "handleRead: Handled first request. " << inputLength - << " bytes in, " << bits << " bits (" << ((float) bits) / 8 - << " bytes) out.\n" << logofs_flush; - #endif - - priority_++; - } - else - { - // - // First of all we get the opcode. - // - - unsigned char inputOpcode = *inputMessage; - - #if defined(TEST) || defined(INFO) - - // - // This is used to test the synchronous - // flush in the parent proxy. - // - - lastRequest_ = inputOpcode; - - #endif - - // - // Check if the request is supported by the - // remote. If not, only handle it locally and - // taint the opcode as a X_NoOperation. Also - // try to short-circuit some replies at this - // side. XSync requests, for example, weight - // for half of the total round-trips. - // - - if (handleTaintRequest(inputOpcode, inputMessage, - inputLength) < 0) - { - return -1; - } - - encodeBuffer.encodeOpcodeValue(inputOpcode, clientCache_ -> opcodeCache); - - // - // Update the current sequence. - // - - clientSequence_++; - clientSequence_ &= 0xffff; - - #ifdef DEBUG - *logofs << "handleRead: Last client sequence number for FD#" - << fd_ << " is " << clientSequence_ << ".\n" - << logofs_flush; - #endif - - // - // If differential compression is disabled - // then use the most simple encoding. - // - - if (control -> LocalDeltaCompression == 0) - { - int result = handleFastReadRequest(encodeBuffer, inputOpcode, - inputMessage, inputLength); - if (result < 0) - { - return -1; - } - else if (result > 0) - { - continue; - } - } - - // - // Go to the message's specific encoding. - // - - switch (inputOpcode) - { - case X_AllocColor: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, - clientCache_ -> colormapCache); - const unsigned char *nextSrc = inputMessage + 8; - unsigned int colorData[3]; - for (unsigned int i = 0; i < 3; i++) - { - unsigned int value = GetUINT(nextSrc, bigEndian_); - encodeBuffer.encodeCachedValue(value, 16, - *(clientCache_ -> allocColorRGBCache[i]), 4); - colorData[i] = value; - nextSrc += 2; - } - - sequenceQueue_.push(clientSequence_, inputOpcode, - colorData[0], colorData[1], colorData[2]); - - priority_++; - } - break; - case X_ReparentWindow: - { - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, bigEndian_), - clientCache_ -> windowCache); - encodeBuffer.encodeValue(GetUINT(inputMessage + 12, bigEndian_), 16, 11); - encodeBuffer.encodeValue(GetUINT(inputMessage + 14, bigEndian_), 16, 11); - } - break; - case X_ChangeProperty: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ChangeProperty); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - unsigned char format = inputMessage[16]; - encodeBuffer.encodeCachedValue(format, 8, - clientCache_ -> changePropertyFormatCache); - unsigned int dataLength = GetULONG(inputMessage + 20, bigEndian_); - encodeBuffer.encodeValue(dataLength, 32, 6); - encodeBuffer.encodeValue(inputMessage[1], 2); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, - clientCache_ -> changePropertyPropertyCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), 29, - clientCache_ -> changePropertyTypeCache, 9); - const unsigned char *nextSrc = inputMessage + 24; - if (format == 8) - { - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, dataLength); - } - else if (format == 32) - { - for (unsigned int i = 0; i < dataLength; i++) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 32, - clientCache_ -> changePropertyData32Cache); - nextSrc += 4; - } - } - else - { - for (unsigned int i = 0; i < dataLength; i++) - { - encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16); - nextSrc += 2; - } - } - } - break; - case X_SendEvent: - { - // - // TODO: This can be improved. In the worst - // cases, it appears to provide a poor 1.6:1 - // ratio. - // - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_SendEvent); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - unsigned int window = GetULONG(inputMessage + 4, bigEndian_); - - if (window == 0 || window == 1) - { - encodeBuffer.encodeBoolValue(1); - encodeBuffer.encodeBoolValue(window); - } - else - { - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeXidValue(window, clientCache_ -> windowCache); - } - - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 32, - clientCache_ -> sendEventMaskCache, 9); - encodeBuffer.encodeCachedValue(*(inputMessage + 12), 8, - clientCache_ -> sendEventCodeCache); - encodeBuffer.encodeCachedValue(*(inputMessage + 13), 8, - clientCache_ -> sendEventByteDataCache); - - unsigned int newSeq = GetUINT(inputMessage + 14, bigEndian_); - unsigned int diffSeq = newSeq - clientCache_ -> sendEventLastSequence; - clientCache_ -> sendEventLastSequence = newSeq; - encodeBuffer.encodeValue(diffSeq, 16, 4); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), 32, - clientCache_ -> sendEventIntDataCache); - - for (unsigned int i = 20; i < 44; i++) - { - encodeBuffer.encodeCachedValue((unsigned int) inputMessage[i], 8, - clientCache_ -> sendEventEventCache); - } - } - break; - case X_ChangeWindowAttributes: - { - encodeBuffer.encodeValue((inputLength - 12) >> 2, 4); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - unsigned int bitmask = GetULONG(inputMessage + 8, bigEndian_); - encodeBuffer.encodeCachedValue(bitmask, 15, - clientCache_ -> createWindowBitmaskCache); - const unsigned char *nextSrc = inputMessage + 12; - unsigned int mask = 0x1; - for (unsigned int j = 0; j < 15; j++) - { - if (bitmask & mask) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 32, - *clientCache_ -> createWindowAttrCache[j]); - nextSrc += 4; - } - mask <<= 1; - } - } - break; - case X_ClearArea: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_ClearArea target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_ClearArea target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_ClearArea target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ClearArea); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - const unsigned char *nextSrc = inputMessage + 8; - for (unsigned int i = 0; i < 4; i++) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *clientCache_ -> clearAreaGeomCache[i], 8); - nextSrc += 2; - } - } - break; - case X_CloseFont: - { - unsigned int font = GetULONG(inputMessage + 4, bigEndian_); - encodeBuffer.encodeValue(font - clientCache_ -> lastFont, 29, 5); - clientCache_ -> lastFont = font; - } - break; - case X_ConfigureWindow: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ConfigureWindow); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - unsigned int bitmask = GetUINT(inputMessage + 8, bigEndian_); - encodeBuffer.encodeCachedValue(bitmask, 7, - clientCache_ -> configureWindowBitmaskCache); - unsigned int mask = 0x1; - const unsigned char *nextSrc = inputMessage + 12; - for (unsigned int i = 0; i < 7; i++) - { - if (bitmask & mask) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), - CONFIGUREWINDOW_FIELD_WIDTH[i], - *clientCache_ -> configureWindowAttrCache[i], 8); - nextSrc += 4; - } - mask <<= 1; - } - } - break; - case X_ConvertSelection: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, - clientCache_ -> convertSelectionRequestorCache, 9); - const unsigned char* nextSrc = inputMessage + 8; - for (unsigned int i = 0; i < 3; i++) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29, - *(clientCache_ -> convertSelectionAtomCache[i]), 9); - nextSrc += 4; - } - unsigned int timestamp = GetULONG(nextSrc, bigEndian_); - encodeBuffer.encodeValue(timestamp - - clientCache_ -> convertSelectionLastTimestamp, 32, 4); - clientCache_ -> convertSelectionLastTimestamp = timestamp; - } - break; - case X_CopyArea: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_CopyArea source id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_CopyArea source id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_CopyArea source id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - t_id = GetULONG(inputMessage + 8, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_CopyArea target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_CopyArea target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_CopyArea target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_CopyArea); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 12, - bigEndian_), clientCache_ -> gcCache); - const unsigned char *nextSrc = inputMessage + 16; - for (unsigned int i = 0; i < 6; i++) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *clientCache_ -> copyAreaGeomCache[i], 8); - nextSrc += 2; - } - } - break; - case X_CopyGC: - { - #ifdef TARGETS - - unsigned int s_g_id = GetULONG(inputMessage + 4, bigEndian_); - unsigned int d_g_id = GetULONG(inputMessage + 8, bigEndian_); - - *logofs << "handleRead: X_CopyGC source gcontext id is " << s_g_id - << " destination gcontext id is " << d_g_id << ".\n" - << logofs_flush; - - #endif - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> gcCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, - bigEndian_), 23, clientCache_ -> createGCBitmaskCache); - } - break; - case X_CopyPlane: - { - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 12, - bigEndian_), clientCache_ -> gcCache); - const unsigned char *nextSrc = inputMessage + 16; - for (unsigned int i = 0; i < 6; i++) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *clientCache_ -> copyPlaneGeomCache[i], 8); - nextSrc += 2; - } - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 28, bigEndian_), 32, - clientCache_ -> copyPlaneBitPlaneCache, 10); - } - break; - case X_CreateGC: - { - #ifdef TARGETS - - unsigned int g_id = GetULONG(inputMessage + 4, bigEndian_); - unsigned int t_id = GetULONG(inputMessage + 8, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_CreateGC id " << g_id - << " target id is pixmap " << t_id - << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_CreateGC id " << g_id - << " target id is window " << t_id - << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_CreateGC id " << g_id - << " target id is unrecognized.\n" - << logofs_flush; - } - - gcontexts.insert(T_gcontexts::value_type(g_id, t_id)); - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_CreateGC); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeNewXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> lastId, clientCache_ -> lastIdCache, - clientCache_ -> gcCache, - clientCache_ -> freeGCCache); - - const unsigned char *nextSrc = inputMessage + 8; - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> drawableCache); - nextSrc += 4; - unsigned int bitmask = GetULONG(nextSrc, bigEndian_); - nextSrc += 4; - encodeBuffer.encodeCachedValue(bitmask, 23, - clientCache_ -> createGCBitmaskCache); - unsigned int mask = 0x1; - for (unsigned int i = 0; i < 23; i++) - { - if (bitmask & mask) - { - unsigned int value = GetULONG(nextSrc, bigEndian_); - nextSrc += 4; - unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i]; - if (fieldWidth <= 4) - { - encodeBuffer.encodeValue(value, fieldWidth); - } - else - { - encodeBuffer.encodeCachedValue(value, fieldWidth, - *clientCache_ -> createGCAttrCache[i]); - } - } - mask <<= 1; - } - } - break; - case X_ChangeGC: - { - #ifdef TARGETS - - unsigned int g_id = GetULONG(inputMessage + 4, bigEndian_); - - T_gcontexts::iterator i = gcontexts.find(g_id); - - if (i != gcontexts.end()) - { - unsigned int t_id = i -> second; - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_ChangeGC gcontext id is " << g_id - << " target id is pixmap " << t_id << ".\n" - << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_ChangeGC gcontext id is " << g_id - << " target id is window " << t_id << ".\n" - << logofs_flush; - } - else - { - *logofs << "handleRead: X_ChangeGC gcontext is " << g_id - << " target id is unrecognized.\n" - << logofs_flush; - } - } - else - { - *logofs << "handleRead: X_ChangeGC gcontext id " << g_id - << " is unrecognized.\n" << logofs_flush; - } - - gcontexts.erase(g_id); - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ChangeGC); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> gcCache); - const unsigned char *nextSrc = inputMessage + 8; - unsigned int bitmask = GetULONG(nextSrc, bigEndian_); - nextSrc += 4; - encodeBuffer.encodeCachedValue(bitmask, 23, - clientCache_ -> createGCBitmaskCache); - unsigned int mask = 0x1; - for (unsigned int i = 0; i < 23; i++) - { - if (bitmask & mask) - { - unsigned int value = GetULONG(nextSrc, bigEndian_); - nextSrc += 4; - unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i]; - if (fieldWidth <= 4) - { - encodeBuffer.encodeValue(value, fieldWidth); - } - else - { - encodeBuffer.encodeCachedValue(value, fieldWidth, - *clientCache_ -> createGCAttrCache[i]); - } - } - mask <<= 1; - } - } - break; - case X_CreatePixmap: - { - #ifdef TARGETS - - *logofs << "handleRead: X_CreatePixmap depth " << (unsigned) inputMessage[1] - << ", pixmap id " << GetULONG(inputMessage + 4, bigEndian_) - << ", drawable " << GetULONG(inputMessage + 8, bigEndian_) - << ", width " << GetUINT(inputMessage + 12, bigEndian_) - << ", height " << GetUINT(inputMessage + 14, bigEndian_) - << ", size " << GetUINT(inputMessage + 2, bigEndian_) << 2 - << ".\n" << logofs_flush; - - unsigned int p_id = GetULONG(inputMessage + 4, bigEndian_); - unsigned short p_sx = GetUINT(inputMessage + 12, bigEndian_); - unsigned short p_sy = GetUINT(inputMessage + 14, bigEndian_); - - *logofs << "handleRead: X_CreatePixmap id is " << p_id - << " width is " << p_sx << " height is " << p_sy - << ".\n" << logofs_flush; - - if (p_sx * p_sy <= 64 * 64) - { - *logofs << "handleRead: X_CreatePixmap id " << p_id << " of size " - << p_sx << "x" << p_sy << "=" << p_sx * p_sy - << " will be painted at client side.\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_CreatePixmap id " << p_id << " of size " - << p_sx << "x" << p_sy << "=" << p_sx * p_sy - << " will be painted at server side.\n" << logofs_flush; - } - - pixmaps.insert(p_id); - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_CreatePixmap); - - hit = handleEncode(encodeBuffer, clientCache_, messageStore, - inputOpcode, inputMessage, inputLength); - } - break; - case X_CreateWindow: - { - #ifdef TARGETS - - unsigned int w_id = GetULONG(inputMessage + 4, bigEndian_); - - *logofs << "handleRead: X_CreateWindow id is " << w_id - << ".\n" << logofs_flush; - - windows.insert(w_id); - - #endif - - unsigned bitmask = GetULONG(inputMessage + 28, bigEndian_); - encodeBuffer.encodeCachedValue((unsigned int) inputMessage[1], 8, - clientCache_ -> depthCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, bigEndian_), - clientCache_ -> windowCache); - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeNewXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> lastId, clientCache_ -> lastIdCache, - clientCache_ -> windowCache, - clientCache_ -> freeWindowCache); - - const unsigned char *nextSrc = inputMessage + 12; - for (unsigned int i = 0; i < 6; i++) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *clientCache_ -> createWindowGeomCache[i], 8); - nextSrc += 2; - } - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 24, - bigEndian_), 29, clientCache_ -> visualCache); - encodeBuffer.encodeCachedValue(bitmask, 15, - clientCache_ -> createWindowBitmaskCache); - nextSrc = inputMessage + 32; - unsigned int mask = 0x1; - for (unsigned int j = 0; j < 15; j++) - { - if (bitmask & mask) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 32, - *clientCache_ -> createWindowAttrCache[j]); - nextSrc += 4; - } - mask <<= 1; - } - } - break; - case X_DeleteProperty: - { - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - encodeBuffer.encodeValue(GetULONG(inputMessage + 8, bigEndian_), 29, 9); - } - break; - case X_FillPoly: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_FillPoly target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_FillPoly target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_FillPoly target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_FillPoly); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - unsigned int numPoints = ((inputLength - 16) >> 2); - - // Since ProtoStep10 (#issue 108) - encodeBuffer.encodeCachedValue(numPoints, 16, - clientCache_ -> fillPolyNumPointsCache, 4); - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, bigEndian_), - clientCache_ -> gcCache); - encodeBuffer.encodeValue((unsigned int) inputMessage[12], 2); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[13]); - int relativeCoordMode = (inputMessage[13] != 0); - const unsigned char *nextSrc = inputMessage + 16; - unsigned int pointIndex = 0; - - for (unsigned int i = 0; i < numPoints; i++) - { - if (relativeCoordMode) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *clientCache_ -> fillPolyXRelCache[pointIndex], 8); - nextSrc += 2; - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *clientCache_ -> fillPolyYRelCache[pointIndex], 8); - nextSrc += 2; - } - else - { - unsigned int x = GetUINT(nextSrc, bigEndian_); - nextSrc += 2; - unsigned int y = GetUINT(nextSrc, bigEndian_); - nextSrc += 2; - unsigned int j; - for (j = 0; j < 8; j++) - if ((x == clientCache_ -> fillPolyRecentX[j]) && - (y == clientCache_ -> fillPolyRecentY[j])) - break; - if (j < 8) - { - encodeBuffer.encodeBoolValue(1); - encodeBuffer.encodeValue(j, 3); - } - else - { - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeCachedValue(x, 16, - *clientCache_ -> fillPolyXAbsCache[pointIndex], 8); - encodeBuffer.encodeCachedValue(y, 16, - *clientCache_ -> fillPolyYAbsCache[pointIndex], 8); - clientCache_ -> fillPolyRecentX[clientCache_ -> fillPolyIndex] = x; - clientCache_ -> fillPolyRecentY[clientCache_ -> fillPolyIndex] = y; - clientCache_ -> fillPolyIndex++; - if (clientCache_ -> fillPolyIndex == 8) - clientCache_ -> fillPolyIndex = 0; - } - } - - if (++pointIndex == 10) pointIndex = 0; - } - } - break; - case X_FreeColors: - { - unsigned int numPixels = GetUINT(inputMessage + 2, bigEndian_) - 3; - encodeBuffer.encodeValue(numPixels, 16, 4); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, - clientCache_ -> colormapCache); - encodeBuffer.encodeValue(GetULONG(inputMessage + 8, bigEndian_), 32, 4); - const unsigned char *nextSrc = inputMessage + 12; - while (numPixels) - { - encodeBuffer.encodeValue(GetULONG(nextSrc, bigEndian_), 32, 8); - nextSrc += 4; - numPixels--; - } - } - break; - case X_FreeCursor: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), - 29, clientCache_ -> cursorCache, 9); - } - break; - case X_FreeGC: - { - #ifdef TARGETS - - unsigned int g_id = GetULONG(inputMessage + 4, bigEndian_); - - T_gcontexts::iterator i = gcontexts.find(g_id); - - if (i != gcontexts.end()) - { - unsigned int t_id = i -> second; - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_FreeGC gcontext id is " << g_id - << " target id is pixmap " << t_id << ".\n" - << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_FreeGC gcontext id is " << g_id - << " target id is window " << t_id << ".\n" - << logofs_flush; - } - else - { - *logofs << "handleRead: X_FreeGC gcontext id is " << g_id - << " target id is unrecognized.\n" - << logofs_flush; - } - } - else - { - *logofs << "handleRead: X_FreeGC gcontext id " << g_id - << " is unrecognized.\n" << logofs_flush; - } - - gcontexts.erase(g_id); - - #endif - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeFreeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> freeGCCache); - } - break; - case X_FreePixmap: - { - #ifdef TARGETS - - unsigned int p_id = GetULONG(inputMessage + 4, bigEndian_); - - *logofs << "handleRead: X_FreePixmap id is " << p_id << ".\n" << logofs_flush; - - pixmaps.erase(p_id); - - #endif - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeFreeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> freeDrawableCache); - } - break; - case X_GetAtomName: - { - encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 29, 9); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GetGeometry: - { - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> drawableCache); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GetInputFocus: - { - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GetModifierMapping: - { - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GetKeyboardMapping: - { - encodeBuffer.encodeValue((unsigned int) inputMessage[4], 8); - encodeBuffer.encodeValue((unsigned int) inputMessage[5], 8); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GetProperty: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_GetProperty); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - unsigned int property = GetULONG(inputMessage + 8, bigEndian_); - - sequenceQueue_.push(clientSequence_, inputOpcode, property); - - priority_++; - - hit = 1; - - break; - } - - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - unsigned int property = GetULONG(inputMessage + 8, bigEndian_); - encodeBuffer.encodeValue(property, 29, 9); - encodeBuffer.encodeValue(GetULONG(inputMessage + 12, bigEndian_), 29, 9); - encodeBuffer.encodeValue(GetULONG(inputMessage + 16, bigEndian_), 32, 2); - encodeBuffer.encodeValue(GetULONG(inputMessage + 20, bigEndian_), 32, 8); - - sequenceQueue_.push(clientSequence_, inputOpcode, property); - - priority_++; - } - break; - case X_GetSelectionOwner: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, - clientCache_ -> getSelectionOwnerSelectionCache, 9); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GrabButton: - { - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, - clientCache_ -> grabButtonEventMaskCache); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[10]); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[11]); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), 29, - clientCache_ -> grabButtonConfineCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), 29, - clientCache_ -> cursorCache, 9); - encodeBuffer.encodeCachedValue(inputMessage[20], 8, - clientCache_ -> grabButtonButtonCache); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 22, bigEndian_), 16, - clientCache_ -> grabButtonModifierCache); - } - break; - case X_GrabPointer: - { - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, - clientCache_ -> grabButtonEventMaskCache); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[10]); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[11]); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, - bigEndian_), 29, - clientCache_ -> grabButtonConfineCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, - bigEndian_), 29, clientCache_ -> cursorCache, 9); - - unsigned int timestamp = GetULONG(inputMessage + 20, bigEndian_); - encodeBuffer.encodeValue(timestamp - - clientCache_ -> grabKeyboardLastTimestamp, 32, 4); - clientCache_ -> grabKeyboardLastTimestamp = timestamp; - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GrabKeyboard: - { - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - unsigned int timestamp = GetULONG(inputMessage + 8, bigEndian_); - encodeBuffer.encodeValue(timestamp - - clientCache_ -> grabKeyboardLastTimestamp, 32, 4); - clientCache_ -> grabKeyboardLastTimestamp = timestamp; - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[12]); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[13]); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GrabServer: - case X_UngrabServer: - case X_NoOperation: - { - } - break; - case X_PolyText8: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_PolyText8 target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_PolyText8 target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_PolyText8 target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyText8); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - unsigned int x = GetUINT(inputMessage + 12, bigEndian_); - int xDiff = x - clientCache_ -> polyTextLastX; - clientCache_ -> polyTextLastX = x; - encodeBuffer.encodeCachedValue(xDiff, 16, - clientCache_ -> polyTextCacheX); - unsigned int y = GetUINT(inputMessage + 14, bigEndian_); - int yDiff = y - clientCache_ -> polyTextLastY; - clientCache_ -> polyTextLastY = y; - encodeBuffer.encodeCachedValue(yDiff, 16, - clientCache_ -> polyTextCacheY); - const unsigned char *end = inputMessage + inputLength - 1; - const unsigned char *nextSrc = inputMessage + 16; - while (nextSrc < end) - { - unsigned int textLength = (unsigned int) *nextSrc++; - encodeBuffer.encodeBoolValue(1); - encodeBuffer.encodeValue(textLength, 8); - if (textLength == 255) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, 1), 29, - clientCache_ -> polyTextFontCache); - nextSrc += 4; - } - else - { - encodeBuffer.encodeCachedValue(*nextSrc++, 8, - clientCache_ -> polyTextDeltaCache); - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, textLength); - nextSrc += textLength; - } - } - encodeBuffer.encodeBoolValue(0); - } - break; - case X_PolyText16: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_PolyText16 target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_PolyText16 target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_PolyText16 target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyText16); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - unsigned int x = GetUINT(inputMessage + 12, bigEndian_); - int xDiff = x - clientCache_ -> polyTextLastX; - clientCache_ -> polyTextLastX = x; - encodeBuffer.encodeCachedValue(xDiff, 16, - clientCache_ -> polyTextCacheX); - unsigned int y = GetUINT(inputMessage + 14, bigEndian_); - int yDiff = y - clientCache_ -> polyTextLastY; - clientCache_ -> polyTextLastY = y; - encodeBuffer.encodeCachedValue(yDiff, 16, - clientCache_ -> polyTextCacheY); - const unsigned char *end = inputMessage + inputLength - 1; - const unsigned char *nextSrc = inputMessage + 16; - while (nextSrc < end) - { - unsigned int textLength = (unsigned int) *nextSrc++; - encodeBuffer.encodeBoolValue(1); - encodeBuffer.encodeValue(textLength, 8); - if (textLength == 255) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, 1), 29, - clientCache_ -> polyTextFontCache); - nextSrc += 4; - } - else - { - encodeBuffer.encodeCachedValue(*nextSrc++, 8, - clientCache_ -> polyTextDeltaCache); - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, textLength * 2); - nextSrc += textLength * 2; - } - } - encodeBuffer.encodeBoolValue(0); - } - break; - case X_ImageText8: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_ImageText8 target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_ImageText8 target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_ImageText8 target id " - << t_id << " is unrecognized.\n" - << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ImageText8); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - unsigned int textLength = (unsigned int) inputMessage[1]; - encodeBuffer.encodeCachedValue(textLength, 8, - clientCache_ -> imageTextLengthCache, 4); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - unsigned int x = GetUINT(inputMessage + 12, bigEndian_); - int xDiff = x - clientCache_ -> imageTextLastX; - clientCache_ -> imageTextLastX = x; - encodeBuffer.encodeCachedValue(xDiff, 16, - clientCache_ -> imageTextCacheX); - unsigned int y = GetUINT(inputMessage + 14, bigEndian_); - int yDiff = y - clientCache_ -> imageTextLastY; - clientCache_ -> imageTextLastY = y; - encodeBuffer.encodeCachedValue(yDiff, 16, - clientCache_ -> imageTextCacheY); - const unsigned char *nextSrc = inputMessage + 16; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, textLength); - } - break; - case X_ImageText16: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_ImageText16 target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_ImageText16 target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_ImageText16 target id " - << t_id << " is unrecognized.\n" - << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ImageText16); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - unsigned int textLength = (unsigned int) inputMessage[1]; - encodeBuffer.encodeCachedValue(textLength, 8, - clientCache_ -> imageTextLengthCache, 4); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - unsigned int x = GetUINT(inputMessage + 12, bigEndian_); - int xDiff = x - clientCache_ -> imageTextLastX; - clientCache_ -> imageTextLastX = x; - encodeBuffer.encodeCachedValue(xDiff, 16, - clientCache_ -> imageTextCacheX); - unsigned int y = GetUINT(inputMessage + 14, bigEndian_); - int yDiff = y - clientCache_ -> imageTextLastY; - clientCache_ -> imageTextLastY = y; - encodeBuffer.encodeCachedValue(yDiff, 16, - clientCache_ -> imageTextCacheY); - const unsigned char *nextSrc = inputMessage + 16; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, textLength * 2); - } - break; - case X_InternAtom: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_InternAtom); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - sequenceQueue_.push(clientSequence_, inputOpcode); - - // - // Set the priority, also if doing so will - // penalize all the well written clients - // using XInternAtoms() to pipeline multi- - // ple replies. - // - - priority_++; - - hit = 1; - - break; - } - - unsigned int nameLength = GetUINT(inputMessage + 4, bigEndian_); - encodeBuffer.encodeValue(nameLength, 16, 6); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - const unsigned char *nextSrc = inputMessage + 8; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, nameLength); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_ListExtensions: - { - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_ListFonts: - { - unsigned int textLength = GetUINT(inputMessage + 6, bigEndian_); - encodeBuffer.encodeValue(textLength, 16, 6); - encodeBuffer.encodeValue(GetUINT(inputMessage + 4, bigEndian_), 16, 6); - const unsigned char* nextSrc = inputMessage + 8; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, textLength); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_LookupColor: - case X_AllocNamedColor: - { - unsigned int textLength = GetUINT(inputMessage + 8, bigEndian_); - encodeBuffer.encodeValue(textLength, 16, 6); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), - 29, clientCache_ -> colormapCache); - const unsigned char *nextSrc = inputMessage + 12; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, textLength); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_MapWindow: - case X_UnmapWindow: - case X_MapSubwindows: - case X_GetWindowAttributes: - case X_DestroyWindow: - case X_DestroySubwindows: - case X_QueryPointer: - case X_QueryTree: - { - #ifdef TARGETS - - if (inputOpcode == X_DestroyWindow) - { - unsigned int w_id = GetULONG(inputMessage + 4, bigEndian_); - - *logofs << "handleRead: X_DestroyWindow id is " - << w_id << ".\n" << logofs_flush; - - windows.erase(w_id); - } - - #endif - - if (inputOpcode == X_DestroyWindow) - { - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeFreeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> freeWindowCache); - } - else - { - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> windowCache); - } - - if ((inputOpcode == X_QueryPointer) || - (inputOpcode == X_GetWindowAttributes) || - (inputOpcode == X_QueryTree)) - { - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - } - break; - case X_OpenFont: - { - unsigned int nameLength = GetUINT(inputMessage + 8, bigEndian_); - encodeBuffer.encodeValue(nameLength, 16, 7); - unsigned int font = GetULONG(inputMessage + 4, bigEndian_); - encodeBuffer.encodeValue(font - clientCache_ -> lastFont, 29, 5); - clientCache_ -> lastFont = font; - const unsigned char *nextSrc = inputMessage + 12; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, nameLength); - } - break; - case X_PolyFillRectangle: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_PolyFillRectangle target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_PolyFillRectangle target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_PolyFillRectangle target id " - << t_id << " is unrecognized.\n" - << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyFillRectangle); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0; - unsigned int lastWidth = 0, lastHeight = 0; - - // - // TODO: Could send the size at the beginning - // instead of a bool at each iteration. - // - - for (unsigned int i = 12; i < inputLength;) - { - unsigned int x = GetUINT(inputMessage + i, bigEndian_); - unsigned int newX = x; - x -= lastX; - lastX = newX; - encodeBuffer.encodeCachedValue(x, 16, - *clientCache_ -> polyFillRectangleCacheX[index], 8); - i += 2; - unsigned int y = GetUINT(inputMessage + i, bigEndian_); - unsigned int newY = y; - y -= lastY; - lastY = newY; - encodeBuffer.encodeCachedValue(y, 16, - *clientCache_ -> polyFillRectangleCacheY[index], 8); - i += 2; - unsigned int width = GetUINT(inputMessage + i, bigEndian_); - unsigned int newWidth = width; - width -= lastWidth; - lastWidth = newWidth; - encodeBuffer.encodeCachedValue(width, 16, - *clientCache_ -> polyFillRectangleCacheWidth[index], 8); - i += 2; - unsigned int height = GetUINT(inputMessage + i, bigEndian_); - unsigned int newHeight = height; - height -= lastHeight; - lastHeight = newHeight; - encodeBuffer.encodeCachedValue(height, 16, - *clientCache_ -> polyFillRectangleCacheHeight[index], 8); - i += 2; - - if (++index == 4) index = 0; - - encodeBuffer.encodeBoolValue((i < inputLength) ? 1 : 0); - } - } - break; - case X_PolyFillArc: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_PolyFillArc target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_PolyFillArc target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_PolyFillArc target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyFillArc); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0; - unsigned int lastWidth = 0, lastHeight = 0; - unsigned int lastAngle1 = 0, lastAngle2 = 0; - - // - // TODO: Could send the size at the beginning - // instead of a bool at each iteration. - // - - for (unsigned int i = 12; i < inputLength;) - { - unsigned int x = GetUINT(inputMessage + i, bigEndian_); - unsigned int newX = x; - x -= lastX; - lastX = newX; - encodeBuffer.encodeCachedValue(x, 16, - *clientCache_ -> polyFillArcCacheX[index], 8); - i += 2; - unsigned int y = GetUINT(inputMessage + i, bigEndian_); - unsigned int newY = y; - y -= lastY; - lastY = newY; - encodeBuffer.encodeCachedValue(y, 16, - *clientCache_ -> polyFillArcCacheY[index], 8); - i += 2; - unsigned int width = GetUINT(inputMessage + i, bigEndian_); - unsigned int newWidth = width; - width -= lastWidth; - lastWidth = newWidth; - encodeBuffer.encodeCachedValue(width, 16, - *clientCache_ -> polyFillArcCacheWidth[index], 8); - i += 2; - unsigned int height = GetUINT(inputMessage + i, bigEndian_); - unsigned int newHeight = height; - height -= lastHeight; - lastHeight = newHeight; - encodeBuffer.encodeCachedValue(height, 16, - *clientCache_ -> polyFillArcCacheHeight[index], 8); - i += 2; - unsigned int angle1 = GetUINT(inputMessage + i, bigEndian_); - unsigned int newAngle1 = angle1; - angle1 -= lastAngle1; - lastAngle1 = newAngle1; - encodeBuffer.encodeCachedValue(angle1, 16, - *clientCache_ -> polyFillArcCacheAngle1[index], 8); - i += 2; - unsigned int angle2 = GetUINT(inputMessage + i, bigEndian_); - unsigned int newAngle2 = angle2; - angle2 -= lastAngle2; - lastAngle2 = newAngle2; - encodeBuffer.encodeCachedValue(angle2, 16, - *clientCache_ -> polyFillArcCacheAngle2[index], 8); - i += 2; - - if (++index == 2) index = 0; - - encodeBuffer.encodeBoolValue((i < inputLength) ? 1 : 0); - } - } - break; - case X_PolyArc: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_PolyArc target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_PolyArc target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_PolyArc target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyArc); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0; - unsigned int lastWidth = 0, lastHeight = 0; - unsigned int lastAngle1 = 0, lastAngle2 = 0; - - // - // TODO: Could send the size at the beginning - // instead of a bool at each iteration. - // - - for (unsigned int i = 12; i < inputLength;) - { - unsigned int x = GetUINT(inputMessage + i, bigEndian_); - unsigned int newX = x; - x -= lastX; - lastX = newX; - encodeBuffer.encodeCachedValue(x, 16, - *clientCache_ -> polyArcCacheX[index], 8); - i += 2; - unsigned int y = GetUINT(inputMessage + i, bigEndian_); - unsigned int newY = y; - y -= lastY; - lastY = newY; - encodeBuffer.encodeCachedValue(y, 16, - *clientCache_ -> polyArcCacheY[index], 8); - i += 2; - unsigned int width = GetUINT(inputMessage + i, bigEndian_); - unsigned int newWidth = width; - width -= lastWidth; - lastWidth = newWidth; - encodeBuffer.encodeCachedValue(width, 16, - *clientCache_ -> polyArcCacheWidth[index], 8); - i += 2; - unsigned int height = GetUINT(inputMessage + i, bigEndian_); - unsigned int newHeight = height; - height -= lastHeight; - lastHeight = newHeight; - encodeBuffer.encodeCachedValue(height, 16, - *clientCache_ -> polyArcCacheHeight[index], 8); - i += 2; - unsigned int angle1 = GetUINT(inputMessage + i, bigEndian_); - unsigned int newAngle1 = angle1; - angle1 -= lastAngle1; - lastAngle1 = newAngle1; - encodeBuffer.encodeCachedValue(angle1, 16, - *clientCache_ -> polyArcCacheAngle1[index], 8); - i += 2; - unsigned int angle2 = GetUINT(inputMessage + i, bigEndian_); - unsigned int newAngle2 = angle2; - angle2 -= lastAngle2; - lastAngle2 = newAngle2; - encodeBuffer.encodeCachedValue(angle2, 16, - *clientCache_ -> polyArcCacheAngle2[index], 8); - i += 2; - - if (++index == 2) index = 0; - - encodeBuffer.encodeBoolValue((i < inputLength) ? 1 : 0); - } - } - break; - case X_PolyPoint: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_PolyPoint target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_PolyPoint target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_PolyPoint target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyPoint); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeValue(GetUINT(inputMessage + 2, bigEndian_) - 3, 16, 4); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, bigEndian_), - clientCache_ -> gcCache); - const unsigned char *nextSrc = inputMessage + 12; - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0; - - for (unsigned int i = 12; i < inputLength; i += 4) - { - unsigned int x = GetUINT(nextSrc, bigEndian_); - nextSrc += 2; - unsigned int tmp = x; - x -= lastX; - lastX = tmp; - encodeBuffer.encodeCachedValue(x, 16, - *clientCache_ -> polyPointCacheX[index], 8); - unsigned int y = GetUINT(nextSrc, bigEndian_); - nextSrc += 2; - tmp = y; - y -= lastY; - lastY = tmp; - encodeBuffer.encodeCachedValue(y, 16, - *clientCache_ -> polyPointCacheY[index], 8); - - if (++index == 2) index = 0; - } - } - break; - case X_PolyLine: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_PolyLine target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_PolyLine target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_PolyLine target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyLine); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeValue(GetUINT(inputMessage + 2, bigEndian_) - 3, 16, 4); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - const unsigned char *nextSrc = inputMessage + 12; - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0; - - for (unsigned int i = 12; i < inputLength; i += 4) - { - unsigned int x = GetUINT(nextSrc, bigEndian_); - nextSrc += 2; - unsigned int tmp = x; - x -= lastX; - lastX = tmp; - encodeBuffer.encodeCachedValue(x, 16, - *clientCache_ -> polyLineCacheX[index], 8); - unsigned int y = GetUINT(nextSrc, bigEndian_); - nextSrc += 2; - tmp = y; - y -= lastY; - lastY = tmp; - encodeBuffer.encodeCachedValue(y, 16, - *clientCache_ -> polyLineCacheY[index], 8); - - if (++index == 2) index = 0; - } - } - break; - case X_PolyRectangle: - { - encodeBuffer.encodeValue((GetUINT(inputMessage + 2, - bigEndian_) - 3) >> 1, 16, 3); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - const unsigned char *end = inputMessage + inputLength; - const unsigned char *nextSrc = inputMessage + 12; - while (nextSrc < end) - { - for (unsigned int i = 0; i < 4; i++) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *clientCache_ -> polyRectangleGeomCache[i], 8); - nextSrc += 2; - } - } - } - break; - case X_PolySegment: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_PolySegment target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_PolySegment target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_PolySegment target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolySegment); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - encodeBuffer.encodeValue((GetUINT(inputMessage + 2, - bigEndian_) - 3) >> 1, 16, 4); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, - bigEndian_), clientCache_ -> gcCache); - const unsigned char *end = inputMessage + inputLength; - const unsigned char *nextSrc = inputMessage + 12; - // unsigned int index = 0; - // unsigned int lastX1, lastY1, lastX2, lastY2; - while (nextSrc < end) - { - unsigned int x = GetUINT(nextSrc, bigEndian_); - nextSrc += 2; - unsigned int xDiff0 = - x - clientCache_ -> polySegmentLastX[0]; - unsigned int xDiff1 = - x - clientCache_ -> polySegmentLastX[1]; - int xDiff0Abs = (int) xDiff0; - if (xDiff0Abs < 0) - xDiff0Abs = -xDiff0Abs; - int xDiff1Abs = (int) xDiff1; - if (xDiff1Abs < 0) - xDiff1Abs = -xDiff1Abs; - - unsigned int y = GetUINT(nextSrc, bigEndian_); - nextSrc += 2; - unsigned int yDiff0 = - y - clientCache_ -> polySegmentLastY[0]; - unsigned int yDiff1 = - y - clientCache_ -> polySegmentLastY[1]; - int yDiff0Abs = (int) yDiff0; - if (yDiff0Abs < 0) - yDiff0Abs = -yDiff0Abs; - int yDiff1Abs = (int) yDiff1; - if (yDiff1Abs < 0) - yDiff1Abs = -yDiff1Abs; - - int diff0 = xDiff0Abs + yDiff0Abs; - int diff1 = xDiff1Abs + yDiff1Abs; - if (diff0 < diff1) - { - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeCachedValue(xDiff0, 16, - clientCache_ -> polySegmentCacheX, 6); - encodeBuffer.encodeCachedValue(yDiff0, 16, - clientCache_ -> polySegmentCacheY, 6); - } - else - { - encodeBuffer.encodeBoolValue(1); - encodeBuffer.encodeCachedValue(xDiff1, 16, - clientCache_ -> polySegmentCacheX, 6); - encodeBuffer.encodeCachedValue(yDiff1, 16, - clientCache_ -> polySegmentCacheY, 6); - } - - clientCache_ -> polySegmentLastX[clientCache_ -> polySegmentCacheIndex] = x; - clientCache_ -> polySegmentLastY[clientCache_ -> polySegmentCacheIndex] = y; - - clientCache_ -> polySegmentCacheIndex = - clientCache_ -> polySegmentCacheIndex == 1 ? 0 : 1; - } - } - break; - case X_PutImage: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_PutImage target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_PutImage target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_PutImage target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PutImage); - - hit = handleEncode(encodeBuffer, clientCache_, messageStore, - inputOpcode, inputMessage, inputLength); - } - break; - case X_QueryBestSize: - { - encodeBuffer.encodeValue((unsigned int)inputMessage[1], 2); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - encodeBuffer.encodeValue(GetUINT(inputMessage + 8, bigEndian_), 16, 8); - encodeBuffer.encodeValue(GetUINT(inputMessage + 10, bigEndian_), 16, 8); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_QueryColors: - { - // Differential encoding. - encodeBuffer.encodeBoolValue(1); - - unsigned int numColors = ((inputLength - 8) >> 2); - encodeBuffer.encodeValue(numColors, 16, 5); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, - clientCache_ -> colormapCache); - const unsigned char *nextSrc = inputMessage + 8; - unsigned int predictedPixel = clientCache_ -> queryColorsLastPixel; - for (unsigned int i = 0; i < numColors; i++) - { - unsigned int pixel = GetULONG(nextSrc, bigEndian_); - nextSrc += 4; - if (pixel == predictedPixel) - encodeBuffer.encodeBoolValue(1); - else - { - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeValue(pixel, 32, 9); - } - if (i == 0) - clientCache_ -> queryColorsLastPixel = pixel; - predictedPixel = pixel + 1; - } - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_QueryExtension: - { - #ifdef TEST - - char data[256]; - - int length = GetUINT(inputMessage + 4, bigEndian_); - - if (length > 256) - { - length = 256; - } - - strncpy(data, (char *) inputMessage + 8, length); - - *(data + length) = '\0'; - - *logofs << "handleRead: Going to query extension '" - << data << "' for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - unsigned int nameLength = GetUINT(inputMessage + 4, bigEndian_); - encodeBuffer.encodeValue(nameLength, 16, 6); - const unsigned char *nextSrc = inputMessage + 8; - - for (; nameLength; nameLength--) - { - encodeBuffer.encodeValue((unsigned int) *nextSrc++, 8); - } - - unsigned int extension = 0; - - if (strncmp((char *) inputMessage + 8, "SHAPE", 5) == 0) - { - extension = X_NXInternalShapeExtension; - } - else if (strncmp((char *) inputMessage + 8, "RENDER", 6) == 0) - { - extension = X_NXInternalRenderExtension; - } - - sequenceQueue_.push(clientSequence_, inputOpcode, extension); - - priority_++; - } - break; - case X_QueryFont: - { - unsigned int font = GetULONG(inputMessage + 4, bigEndian_); - encodeBuffer.encodeValue(font - clientCache_ -> lastFont, 29, 5); - clientCache_ -> lastFont = font; - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_SetClipRectangles: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_SetClipRectangles); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - hit = 1; - - break; - } - - unsigned int numRectangles = ((inputLength - 12) >> 3); - - // Since ProtoStep9 (#issue 108) - encodeBuffer.encodeValue(numRectangles, 15, 4); - - encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> gcCache); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, - clientCache_ -> setClipRectanglesXCache, 8); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 10, bigEndian_), 16, - clientCache_ -> setClipRectanglesYCache, 8); - const unsigned char *nextSrc = inputMessage + 12; - for (unsigned int i = 0; i < numRectangles; i++) - { - for (unsigned int j = 0; j < 4; j++) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *clientCache_ -> setClipRectanglesGeomCache[j], 8); - nextSrc += 2; - } - } - } - break; - case X_SetDashes: - { - unsigned int numDashes = GetUINT(inputMessage + 10, bigEndian_); - encodeBuffer.encodeCachedValue(numDashes, 16, - clientCache_ -> setDashesLengthCache, 5); - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), - clientCache_ -> gcCache); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, - clientCache_ -> setDashesOffsetCache, 5); - const unsigned char *nextSrc = inputMessage + 12; - for (unsigned int i = 0; i < numDashes; i++) - encodeBuffer.encodeCachedValue(*nextSrc++, 8, - clientCache_ -> setDashesDashCache_[i & 1], 5); - } - break; - case X_SetSelectionOwner: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, - clientCache_ -> setSelectionOwnerCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, - clientCache_ -> getSelectionOwnerSelectionCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), 32, - clientCache_ -> setSelectionOwnerTimestampCache, 9); - } - break; - case X_TranslateCoords: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_TranslateCoords source id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_TranslateCoords source id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_TranslateCoords source id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - t_id = GetULONG(inputMessage + 8, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_TranslateCoords target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_TranslateCoords target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_TranslateCoords target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_TranslateCoords); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - - hit = 1; - - break; - } - - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, - clientCache_ -> translateCoordsSrcCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, - clientCache_ -> translateCoordsDstCache, 9); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 12, bigEndian_), 16, - clientCache_ -> translateCoordsXCache, 8); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 14, bigEndian_), 16, - clientCache_ -> translateCoordsYCache, 8); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GetImage: - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_GetImage source id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_GetImage source id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_GetImage source id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_GetImage); - - if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, - inputMessage, inputLength)) - { - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - - hit = 1; - - break; - } - - // Format. - encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2); - // Drawable. - encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, - bigEndian_), clientCache_ -> drawableCache); - // X. - unsigned int x = GetUINT(inputMessage + 8, bigEndian_); - int xDiff = x - clientCache_ -> putImageLastX; - clientCache_ -> putImageLastX = x; - encodeBuffer.encodeCachedValue(xDiff, 16, - clientCache_ -> putImageXCache, 8); - // Y. - unsigned int y = GetUINT(inputMessage + 10, bigEndian_); - int yDiff = y - clientCache_ -> putImageLastY; - clientCache_ -> putImageLastY = y; - encodeBuffer.encodeCachedValue(yDiff, 16, - clientCache_ -> putImageYCache, 8); - // Width. - unsigned int width = GetUINT(inputMessage + 12, bigEndian_); - encodeBuffer.encodeCachedValue(width, 16, - clientCache_ -> putImageWidthCache, 8); - // Height. - unsigned int height = GetUINT(inputMessage + 14, bigEndian_); - encodeBuffer.encodeCachedValue(height, 16, - clientCache_ -> putImageHeightCache, 8); - // Plane mask. - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), 32, - clientCache_ -> getImagePlaneMaskCache, 5); - - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GetPointerMapping: - { - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - case X_GetKeyboardControl: - { - sequenceQueue_.push(clientSequence_, inputOpcode); - - priority_++; - } - break; - default: - { - if (inputOpcode == opcodeStore_ -> renderExtension) - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXInternalRenderExtension); - - hit = handleEncode(encodeBuffer, clientCache_, messageStore, - inputOpcode, inputMessage, inputLength); - } - else if (inputOpcode == opcodeStore_ -> shapeExtension) - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXInternalShapeExtension); - - hit = handleEncode(encodeBuffer, clientCache_, messageStore, - inputOpcode, inputMessage, inputLength); - } - else if (inputOpcode == opcodeStore_ -> putPackedImage) - { - #ifdef TARGETS - - unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); - - if (pixmaps.find(t_id) != pixmaps.end()) - { - *logofs << "handleRead: X_NXPutPackedImage target id is pixmap " - << t_id << ".\n" << logofs_flush; - } - else if (windows.find(t_id) != windows.end()) - { - *logofs << "handleRead: X_NXPutPackedImage target id is window " - << t_id << ".\n" << logofs_flush; - } - else - { - *logofs << "handleRead: X_NXPutPackedImage target id " << t_id - << " is unrecognized.\n" << logofs_flush; - } - - #endif - - #ifdef DEBUG - *logofs << "handleRead: Encoding packed image request for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - // - // The field carries the destination data - // length. We add the request's size of - // the final X_PutImage. - // - - unsigned int outputLength = GetULONG(inputMessage + 20, bigEndian_) + 24; - - statistics -> addPackedBytesIn(inputLength); - - statistics -> addPackedBytesOut(outputLength); - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXPutPackedImage); - - hit = handleEncode(encodeBuffer, clientCache_, messageStore, - inputOpcode, inputMessage, inputLength); - } - else if (inputOpcode == opcodeStore_ -> setUnpackColormap) - { - #ifdef DEBUG - *logofs << "handleRead: Encoding set unpack colormap request " - << "for FD#" << fd_ << " with size " << inputLength - << ".\n" << logofs_flush; - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXSetUnpackColormap); - - hit = handleEncode(encodeBuffer, clientCache_, messageStore, - inputOpcode, inputMessage, inputLength); - } - else if (inputOpcode == opcodeStore_ -> setUnpackAlpha) - { - #ifdef DEBUG - *logofs << "handleRead: Encoding set unpack alpha request " - << "for FD#" << fd_ << " with size " << inputLength - << ".\n" << logofs_flush; - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXSetUnpackAlpha); - - hit = handleEncode(encodeBuffer, clientCache_, messageStore, - inputOpcode, inputMessage, inputLength); - } - else if (inputOpcode == opcodeStore_ -> setUnpackGeometry) - { - #ifdef DEBUG - *logofs << "handleRead: Encoding set unpack geometry request " - << "for FD#" << fd_ << " with size " << inputLength - << ".\n" << logofs_flush; - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXSetUnpackGeometry); - - hit = handleEncode(encodeBuffer, clientCache_, messageStore, - inputOpcode, inputMessage, inputLength); - } - else if (inputOpcode == opcodeStore_ -> startSplit) - { - if (handleStartSplitRequest(encodeBuffer, inputOpcode, - inputMessage, inputLength) < 0) - { - return -1; - } - } - else if (inputOpcode == opcodeStore_ -> endSplit) - { - if (handleEndSplitRequest(encodeBuffer, inputOpcode, - inputMessage, inputLength) < 0) - { - return -1; - } - } - else if (inputOpcode == opcodeStore_ -> commitSplit) - { - if (handleCommitSplitRequest(encodeBuffer, inputOpcode, - inputMessage, inputLength) < 0) - { - return -1; - } - } - else if (inputOpcode == opcodeStore_ -> abortSplit) - { - if (handleAbortSplitRequest(encodeBuffer, inputOpcode, - inputMessage, inputLength) < 0) - { - return -1; - } - } - else if (inputOpcode == opcodeStore_ -> finishSplit) - { - if (handleFinishSplitRequest(encodeBuffer, inputOpcode, - inputMessage, inputLength) < 0) - { - return -1; - } - } - else if (inputOpcode == opcodeStore_ -> freeSplit) - { - #ifdef DEBUG - *logofs << "handleRead: Encoding free split request " - << "for FD#" << fd_ << " with size " << inputLength - << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(*(inputMessage + 1), 8, - clientCache_ -> resourceCache); - } - else if (inputOpcode == opcodeStore_ -> freeUnpack) - { - #ifdef DEBUG - *logofs << "handleRead: Encoding free unpack request " - << "for FD#" << fd_ << " with size " << inputLength - << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(*(inputMessage + 1), 8, - clientCache_ -> resourceCache); - } - else if (inputOpcode == opcodeStore_ -> getControlParameters) - { - #ifdef DEBUG - *logofs << "handleRead: Encoding get control parameters " - << "request for FD#" << fd_ << " with size " - << inputLength << ".\n" << logofs_flush; - #endif - - // - // Add the reply to the write buffer. If found - // to contain a message, it it will be flushed - // to the X client before leaving the loop. - // - - unsigned char *reply = writeBuffer_.addMessage(32); - - *(reply + 0) = X_Reply; - - PutUINT(clientSequence_, reply + 2, bigEndian_); - - PutULONG(0, reply + 4, bigEndian_); - - // - // Save the sequence number we used - // to auto-generate this reply. - // - - lastSequence_ = clientSequence_; - - #ifdef TEST - *logofs << "handleRead: Registered " << lastSequence_ - << " as last auto-generated sequence number.\n" - << logofs_flush; - #endif - - *(reply + 1) = control -> LinkMode; - - *(reply + 8) = control -> LocalVersionMajor; - *(reply + 9) = control -> LocalVersionMinor; - *(reply + 10) = control -> LocalVersionPatch; - - *(reply + 11) = control -> RemoteVersionMajor; - *(reply + 12) = control -> RemoteVersionMinor; - *(reply + 13) = control -> RemoteVersionPatch; - - PutUINT(control -> SplitTimeout, reply + 14, bigEndian_); - PutUINT(control -> MotionTimeout, reply + 16, bigEndian_); - - *(reply + 18) = control -> SplitMode; - - PutULONG(control -> SplitDataThreshold, reply + 20, bigEndian_); - - *(reply + 24) = control -> PackMethod; - *(reply + 25) = control -> PackQuality; - - *(reply + 26) = control -> LocalDataCompressionLevel; - *(reply + 27) = control -> LocalStreamCompressionLevel; - *(reply + 28) = control -> LocalDeltaCompression; - - *(reply + 29) = (control -> LocalDeltaCompression == 1 && - control -> PersistentCacheEnableLoad == 1); - *(reply + 30) = (control -> LocalDeltaCompression == 1 && - control -> PersistentCacheEnableSave == 1); - *(reply + 31) = (control -> LocalDeltaCompression == 1 && - control -> PersistentCacheEnableLoad == 1 && - control -> PersistentCacheName != NULL); - - if (handleFlush(flush_if_any) < 0) - { - return -1; - } - } - else if (inputOpcode == opcodeStore_ -> getCleanupParameters) - { - #ifdef WARNING - *logofs << "handleRead: WARNING! Encoding fake get cleanup " - << "parameters request for FD#" << fd_ << " with size " - << inputLength << ".\n" << logofs_flush; - #endif - } - else if (inputOpcode == opcodeStore_ -> getImageParameters) - { - #ifdef WARNING - *logofs << "handleRead: WARNING! Encoding fake get cleanup " - << "parameters request for FD#" << fd_ << " with size " - << inputLength << ".\n" << logofs_flush; - #endif - } - else if (inputOpcode == opcodeStore_ -> getUnpackParameters) - { - #ifdef DEBUG - *logofs << "handleRead: Encoding get unpack parameters " - << "request for FD#" << fd_ << " with size " - << inputLength << ".\n" << logofs_flush; - #endif - - sequenceQueue_.push(clientSequence_, inputOpcode); - } - else if (inputOpcode == opcodeStore_ -> getShmemParameters) - { - if (handleShmemRequest(encodeBuffer, inputOpcode, - inputMessage, inputLength) < 0) - { - return -1; - } - } - else if (inputOpcode == opcodeStore_ -> setExposeParameters) - { - // - // Enable or disable expose events - // coming from the real server. - // - - encodeBuffer.encodeBoolValue(*(inputMessage + 4)); - encodeBuffer.encodeBoolValue(*(inputMessage + 5)); - encodeBuffer.encodeBoolValue(*(inputMessage + 6)); - } - else if (inputOpcode == opcodeStore_ -> setCacheParameters) - { - if (handleCacheRequest(encodeBuffer, inputOpcode, - inputMessage, inputLength) < 0) - { - return -1; - } - } - else if (inputOpcode == opcodeStore_ -> getFontParameters) - { - if (handleFontRequest(encodeBuffer, inputOpcode, - inputMessage, inputLength) < 0) - { - return -1; - } - } - else - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXInternalGenericRequest); - - hit = handleEncode(encodeBuffer, clientCache_, messageStore, - inputOpcode, inputMessage, inputLength); - - // - // Don't flush if the opcode is unrecognized. - // We may optionally flush it is an extension - // but would penalize the well written clients. - // - // if (inputOpcode > 127) - // { - // priority_++; - // } - // - } - } - } // End of switch on opcode. - - int bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) - - const char *cacheString = (hit ? "cached " : ""); - - *logofs << "handleRead: Handled " << cacheString << "request OPCODE#" - << (unsigned int) inputOpcode << " (" << DumpOpcode(inputOpcode) - << ")" << " for FD#" << fd_ << " sequence " << clientSequence_ - << ". " << inputLength << " bytes in, " << bits << " bits (" - << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; - - #endif - - if (hit) - { - statistics -> addCachedRequest(inputOpcode); - } - - statistics -> addRequestBits(inputOpcode, inputLength << 3, bits); - - if (inputOpcode == opcodeStore_ -> renderExtension) - { - if (hit) - { - statistics -> addRenderCachedRequest(*(inputMessage + 1)); - } - - statistics -> addRenderRequestBits(*(inputMessage + 1), inputLength << 3, bits); - } - - } // End if (firstRequest_)... else ... - - } // End of while ((inputMessage = readBuffer_.getMessage(inputLength)) != 0) ... - - // - // Check if we need to flush because of - // prioritized data. - // - - if (priority_ > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleRead: WARNING! Requesting flush " - << "because of " << priority_ << " prioritized " - << "messages for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - if (proxy -> handleAsyncPriority() < 0) - { - return -1; - } - - // - // Reset the priority flag. - // - - priority_ = 0; - } - - // - // Flush if we exceeded the token length. - // - - if (proxy -> canAsyncFlush() == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleRead: WARNING! Requesting flush " - << "because of token length exceeded.\n" - << logofs_flush; - #endif - - if (proxy -> handleAsyncFlush() < 0) - { - return -1; - } - } - - #if defined(TEST) || defined(INFO) - - if (transport_ -> pending() != 0 || - readBuffer_.checkMessage() != 0) - { - *logofs << "handleRead: PANIC! Buffer for X descriptor FD#" - << fd_ << " has " << transport_ -> pending() - << " bytes to read.\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - // - // Reset the read buffer. - // - - readBuffer_.fullReset(); - - return 1; -} - -// -// End of handleRead(). -// - -// -// Beginning of handleWrite(). -// - -int ClientChannel::handleWrite(const unsigned char *message, unsigned int length) -{ - #ifdef TEST - *logofs << "handleWrite: Called for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - // - // Create the buffer from which to - // decode messages. - // - - DecodeBuffer decodeBuffer(message, length); - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "handleWrite: Decoding messages for FD#" << fd_ - << " with " << length << " bytes in the buffer.\n" - << logofs_flush; - #endif - - if (firstReply_) - { - #ifdef TEST - *logofs << "handleWrite: First reply detected.\n" << logofs_flush; - #endif - - unsigned int outputOpcode; - - decodeBuffer.decodeValue(outputOpcode, 8); - unsigned int secondByte; - decodeBuffer.decodeValue(secondByte, 8); - unsigned int major; - decodeBuffer.decodeValue(major, 16); - unsigned int minor; - decodeBuffer.decodeValue(minor, 16); - unsigned int extraLength; - decodeBuffer.decodeValue(extraLength, 16); - unsigned int outputLength = 8 + (extraLength << 2); - - unsigned char *outputMessage = writeBuffer_.addMessage(outputLength); - *outputMessage = (unsigned char) outputOpcode; - outputMessage[1] = (unsigned char) secondByte; - PutUINT(major, outputMessage + 2, bigEndian_); - PutUINT(minor, outputMessage + 4, bigEndian_); - PutUINT(extraLength, outputMessage + 6, bigEndian_); - unsigned char *nextDest = outputMessage + 8; - unsigned int cached; - decodeBuffer.decodeBoolValue(cached); - - if (cached) - { - memcpy(nextDest, ServerCache::lastInitReply.getData(), outputLength - 8); - } - else - { - for (unsigned i = 8; i < outputLength; i++) - { - unsigned int nextByte; - decodeBuffer.decodeValue(nextByte, 8); - *nextDest++ = (unsigned char) nextByte; - } - - ServerCache::lastInitReply.set(outputLength - 8, outputMessage + 8); - } - - imageByteOrder_ = outputMessage[30]; - bitmapBitOrder_ = outputMessage[31]; - scanlineUnit_ = outputMessage[32]; - scanlinePad_ = outputMessage[33]; - - firstReply_ = 0; - - } // End of if (firstReply_) - - // - // This was previously in a 'else' block. - // Due to the way the first request was - // handled, we could not decode multiple - // messages in the first frame. - // - - { // Start of the decoding block. - - #ifdef DEBUG - *logofs << "handleWrite: Starting loop on opcodes.\n" - << logofs_flush; - #endif - - unsigned char outputOpcode; - - // - // NX client needs this line to consider - // the initialization phase successfully - // completed. - // - - if (firstClient_ == -1) - { - cerr << "Info" << ": Established X client connection.\n" ; - - firstClient_ = fd_; - } - - while (decodeBuffer.decodeOpcodeValue(outputOpcode, serverCache_ -> opcodeCache, 1)) - { - #ifdef DEBUG - *logofs << "handleWrite: Decoded a new OPCODE#" - << (unsigned int) outputOpcode << ".\n" - << logofs_flush; - #endif - - unsigned char *outputMessage = NULL; - unsigned int outputLength = 0; - - // - // General-purpose temp variables - // for decoding ints and chars. - // - - unsigned int value = 0; - unsigned char cValue = 0; - - // - // Check first if we need to abort any split, - // then if this is a reply, finally if it is - // en event or error. - // - - if (outputOpcode == opcodeStore_ -> splitEvent) - { - // - // It's an abort split, not a normal - // burst of proxy data. - // - - handleSplitEvent(decodeBuffer); - - continue; - } - else if (outputOpcode == X_Reply) - { - #ifdef DEBUG - *logofs << "handleWrite: Decoding sequence number of reply.\n" - << logofs_flush; - #endif - - unsigned int sequenceNum; - unsigned int sequenceDiff; - - decodeBuffer.decodeCachedValue(sequenceDiff, 16, - serverCache_ -> replySequenceCache, 7); - - sequenceNum = (serverSequence_ + sequenceDiff) & 0xffff; - - serverSequence_ = sequenceNum; - - #ifdef DEBUG - *logofs << "handleWrite: Last server sequence number for FD#" - << fd_ << " is " << serverSequence_ << " with " - << "difference " << sequenceDiff << ".\n" - << logofs_flush; - #endif - - // - // In case of reply we can follow the X server and - // override any event's sequence number generated - // by this side. - // - - #ifdef TEST - *logofs << "handleWrite: Updating last event's sequence " - << lastSequence_ << " to reply's sequence number " - << serverSequence_ << " for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - lastSequence_ = serverSequence_; - - unsigned short int requestSequenceNum; - unsigned char requestOpcode; - - #ifdef DEBUG - - requestSequenceNum = 0; - requestOpcode = 0; - - *logofs << "handleWrite: Peek of sequence number returns "; - - *logofs << sequenceQueue_.peek(requestSequenceNum, requestOpcode); - - *logofs << " with sequence " << requestSequenceNum << " and opcode " - << (unsigned int) requestOpcode << ".\n" << logofs_flush; - - #endif - - if (sequenceQueue_.peek(requestSequenceNum, requestOpcode) == 1 && - (requestSequenceNum == sequenceNum)) - { - unsigned int requestData[3]; - - sequenceQueue_.pop(requestSequenceNum, requestOpcode, - requestData[0], requestData[1], requestData[2]); - - #ifdef DEBUG - *logofs << "handleWrite: Identified reply to OPCODE#" - << (unsigned int) requestOpcode << ".\n" - << logofs_flush; - #endif - - // - // Is differential encoding disabled? - // - - if (control -> RemoteDeltaCompression == 0) - { - int result = handleFastWriteReply(decodeBuffer, requestOpcode, - outputMessage, outputLength); - if (result < 0) - { - return -1; - } - else if (result > 0) - { - continue; - } - } - - switch (requestOpcode) - { - case X_AllocColor: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - unsigned char *nextDest = outputMessage + 8; - for (unsigned int i = 0; i < 3; i++) - { - decodeBuffer.decodeBoolValue(value); - if (value) - { - PutUINT(requestData[i], nextDest, bigEndian_); - } - else - { - decodeBuffer.decodeValue(value, 16, 6); - PutUINT(requestData[i] + value, nextDest, bigEndian_); - } - nextDest += 2; - } - decodeBuffer.decodeValue(value, 32, 9); - PutULONG(value, outputMessage + 16, bigEndian_); - } - break; - case X_GetAtomName: - { - unsigned int nameLength; - decodeBuffer.decodeValue(nameLength, 16, 6); - outputLength = RoundUp4(nameLength) + 32; - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(nameLength, outputMessage + 8, bigEndian_); - unsigned char* nextDest = outputMessage + 32; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, nameLength); - } - break; - case X_GetGeometry: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(cValue, 8, - serverCache_ -> depthCache); - outputMessage[1] = cValue; - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> getGeometryRootCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - for (unsigned int i = 0; i < 5; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *serverCache_ -> getGeometryGeomCache[i], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - } - break; - case X_GetInputFocus: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 2); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> getInputFocusWindowCache); - PutULONG(value, outputMessage + 8, bigEndian_); - } - break; - case X_GetKeyboardMapping: - { - decodeBuffer.decodeBoolValue(value); - if (value) - { - unsigned int dataLength = - ServerCache::getKeyboardMappingLastMap.getLength(); - outputLength = 32 + dataLength; - outputMessage = writeBuffer_.addMessage(outputLength); - outputMessage[1] = - ServerCache::getKeyboardMappingLastKeysymsPerKeycode; - memcpy(outputMessage + 32, - ServerCache::getKeyboardMappingLastMap.getData(), - dataLength); - break; - } - unsigned int numKeycodes; - decodeBuffer.decodeValue(numKeycodes, 8); - unsigned int keysymsPerKeycode; - decodeBuffer.decodeValue(keysymsPerKeycode, 8, 4); - ServerCache::getKeyboardMappingLastKeysymsPerKeycode = - keysymsPerKeycode; - outputLength = 32 + numKeycodes * keysymsPerKeycode * 4; - outputMessage = writeBuffer_.addMessage(outputLength); - outputMessage[1] = (unsigned char) keysymsPerKeycode; - unsigned char *nextDest = outputMessage + 32; - unsigned char previous = 0; - for (unsigned int count = numKeycodes * keysymsPerKeycode; - count; --count) - { - decodeBuffer.decodeBoolValue(value); - if (value) - PutULONG((unsigned int) NoSymbol, nextDest, bigEndian_); - else - { - unsigned int keysym; - decodeBuffer.decodeCachedValue(keysym, 24, - serverCache_ -> getKeyboardMappingKeysymCache, 9); - decodeBuffer.decodeCachedValue(cValue, 8, - serverCache_ -> getKeyboardMappingLastByteCache, 5); - previous += cValue; - PutULONG((keysym << 8) | previous, nextDest, bigEndian_); - } - nextDest += 4; - } - ServerCache::getKeyboardMappingLastMap.set(outputLength - 32, - outputMessage + 32); - } - break; - case X_GetModifierMapping: - { - unsigned int keycodesPerModifier; - decodeBuffer.decodeValue(keycodesPerModifier, 8); - outputLength = 32 + (keycodesPerModifier << 3); - outputMessage = writeBuffer_.addMessage(outputLength); - outputMessage[1] = (unsigned char) keycodesPerModifier; - unsigned char *nextDest = outputMessage + 32; - decodeBuffer.decodeBoolValue(value); - if (value) - { - memcpy(outputMessage + 32, - ServerCache::getModifierMappingLastMap.getData(), - ServerCache::getModifierMappingLastMap.getLength()); - break; - } - for (unsigned int count = outputLength - 32; count; count--) - { - decodeBuffer.decodeBoolValue(value); - if (value) - *nextDest++ = 0; - else - { - decodeBuffer.decodeValue(value, 8); - *nextDest++ = value; - } - } - ServerCache::getModifierMappingLastMap.set(outputLength - 32, - outputMessage + 32); - } - break; - case X_GetProperty: - { - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_GetProperty); - - handleDecode(decodeBuffer, serverCache_, messageStore, - requestOpcode, outputMessage, outputLength); - } - break; - case X_GetSelectionOwner: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> getSelectionOwnerCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - } - break; - case X_GetWindowAttributes: - { - outputLength = 44; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 2); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> visualCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> getWindowAttributesClassCache, 3); - PutUINT(value, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(cValue, 8, - serverCache_ -> getWindowAttributesBitGravityCache); - outputMessage[14] = cValue; - decodeBuffer.decodeCachedValue(cValue, 8, - serverCache_ -> getWindowAttributesWinGravityCache); - outputMessage[15] = cValue; - decodeBuffer.decodeCachedValue(value, 32, - serverCache_ -> getWindowAttributesPlanesCache, 9); - PutULONG(value, outputMessage + 16, bigEndian_); - decodeBuffer.decodeCachedValue(value, 32, - serverCache_ -> getWindowAttributesPixelCache, 9); - PutULONG(value, outputMessage + 20, bigEndian_); - decodeBuffer.decodeBoolValue(value); - outputMessage[24] = (unsigned char) value; - decodeBuffer.decodeBoolValue(value); - outputMessage[25] = (unsigned char) value; - decodeBuffer.decodeValue(value, 2); - outputMessage[26] = (unsigned char) value; - decodeBuffer.decodeBoolValue(value); - outputMessage[27] = (unsigned char) value; - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> colormapCache, 9); - PutULONG(value, outputMessage + 28, bigEndian_); - decodeBuffer.decodeCachedValue(value, 32, - serverCache_ -> getWindowAttributesAllEventsCache); - PutULONG(value, outputMessage + 32, bigEndian_); - decodeBuffer.decodeCachedValue(value, 32, - serverCache_ -> getWindowAttributesYourEventsCache); - PutULONG(value, outputMessage + 36, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> getWindowAttributesDontPropagateCache); - PutUINT(value, outputMessage + 40, bigEndian_); - } - break; - case X_GrabKeyboard: - case X_GrabPointer: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 3); - outputMessage[1] = (unsigned char) value; - } - break; - case X_InternAtom: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 29, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - } - break; - case X_ListExtensions: - { - decodeBuffer.decodeValue(value, 32, 8); - outputLength = 32 + (value << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - unsigned int numExtensions; - decodeBuffer.decodeValue(numExtensions, 8); - outputMessage[1] = (unsigned char) numExtensions; - unsigned char *nextDest = outputMessage + 32; - for (; numExtensions; numExtensions--) - { - unsigned int length; - decodeBuffer.decodeValue(length, 8); - *nextDest++ = (unsigned char) length; - for (; length; length--) - { - decodeBuffer.decodeValue(value, 8); - *nextDest++ = value; - } - } - } - break; - case X_ListFonts: - { - // - // Differential compression can achieve a 12:1 to 14:1 - // ratio, while the best ZLIB compression can achieve - // a mere 4:1 to 5:1. In the first case, though, the - // huge amount of data constituting the message would - // be stored uncompressed at the remote side. We need - // to find a compromise. The solution is to use diffe- - // rential compression at startup and ZLIB compression - // later on. - // - - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_ListFonts); - - if (handleDecodeCached(decodeBuffer, serverCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - decodeBuffer.decodeValue(value, 32, 8); - outputLength = 32 + (value << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - unsigned int numFonts; - decodeBuffer.decodeValue(numFonts, 16, 6); - PutUINT(numFonts, outputMessage + 8, bigEndian_); - - // Differential or plain data compression? - decodeBuffer.decodeBoolValue(value); - - if (value) - { - unsigned char* nextDest = outputMessage + 32; - for (; numFonts; numFonts--) - { - unsigned int length; - decodeBuffer.decodeValue(length, 8); - *nextDest++ = (unsigned char)length; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, length); - nextDest += length; - } - - handleSave(messageStore, outputMessage, outputLength); - } - else - { - const unsigned char *compressedData = NULL; - unsigned int compressedDataSize = 0; - - int decompressed = handleDecompress(decodeBuffer, requestOpcode, messageStore -> dataOffset, - outputMessage, outputLength, compressedData, - compressedDataSize); - if (decompressed < 0) - { - return -1; - } - else if (decompressed > 0) - { - handleSave(messageStore, outputMessage, outputLength, - compressedData, compressedDataSize); - } - else - { - handleSave(messageStore, outputMessage, outputLength); - } - } - } - break; - case X_LookupColor: - case X_AllocNamedColor: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - unsigned char *nextDest = outputMessage + 8; - if (requestOpcode == X_AllocNamedColor) - { - decodeBuffer.decodeValue(value, 32, 9); - PutULONG(value, nextDest, bigEndian_); - nextDest += 4; - } - unsigned int count = 3; - do - { - decodeBuffer.decodeValue(value, 16, 9); - PutUINT(value, nextDest, bigEndian_); - unsigned int visualColor; - decodeBuffer.decodeValue(visualColor, 16, 5); - visualColor += value; - visualColor &= 0xffff; - PutUINT(visualColor, nextDest + 6, bigEndian_); - nextDest += 2; - } - while (--count); - } - break; - case X_QueryBestSize: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 16, 8); - PutUINT(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeValue(value, 16, 8); - PutUINT(value, outputMessage + 10, bigEndian_); - } - break; - case X_QueryColors: - { - // Differential or plain data compression? - decodeBuffer.decodeBoolValue(value); - - if (value) - { - decodeBuffer.decodeBoolValue(value); - if (value) - { - unsigned int numColors = - serverCache_ -> queryColorsLastReply.getLength() / 6; - outputLength = 32 + (numColors << 3); - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(numColors, outputMessage + 8, bigEndian_); - const unsigned char *nextSrc = - serverCache_ -> queryColorsLastReply.getData(); - unsigned char *nextDest = outputMessage + 32; - for (; numColors; numColors--) - { - for (unsigned int i = 0; i < 6; i++) - *nextDest++ = *nextSrc++; - nextDest += 2; - } - } - else - { - unsigned int numColors; - decodeBuffer.decodeValue(numColors, 16, 5); - outputLength = 32 + (numColors << 3); - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(numColors, outputMessage + 8, bigEndian_); - unsigned char *nextDest = outputMessage + 32; - for (unsigned int c = 0; c < numColors; c++) - { - for (unsigned int i = 0; i < 3; i++) - { - decodeBuffer.decodeValue(value, 16); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - } - serverCache_ -> queryColorsLastReply.set(numColors * 6, - outputMessage + 32); - const unsigned char *nextSrc = nextDest - 1; - nextDest = outputMessage + 32 + ((numColors - 1) << 3) + 5; - for (; numColors > 1; numColors--) - { - for (unsigned int i = 0; i < 6; i++) - *nextDest-- = *nextSrc--; - nextDest -= 2; - } - } - } - else - { - // Reply length. - unsigned int numColors; - decodeBuffer.decodeValue(numColors, 16, 5); - outputLength = 32 + (numColors << 3); - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(numColors, outputMessage + 8, bigEndian_); - - const unsigned char *compressedData = NULL; - unsigned int compressedDataSize = 0; - - int decompressed = handleDecompress(decodeBuffer, requestOpcode, 32, - outputMessage, outputLength, compressedData, - compressedDataSize); - if (decompressed < 0) - { - return -1; - } - } - } - break; - case X_QueryExtension: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeBoolValue(value); - outputMessage[8] = (unsigned char) value; - decodeBuffer.decodeValue(value, 8); - outputMessage[9] = (unsigned char) value; - decodeBuffer.decodeValue(value, 8); - outputMessage[10] = (unsigned char) value; - decodeBuffer.decodeValue(value, 8); - outputMessage[11] = (unsigned char) value; - - // - // We use a predefined opcode to address - // extensions' message stores, while real - // opcodes are used for communication with - // X server and clients. - // - - if (requestData[0] == X_NXInternalShapeExtension) - { - opcodeStore_ -> shapeExtension = outputMessage[9]; - - #ifdef TEST - *logofs << "handleWrite: Shape extension opcode for FD#" << fd_ - << " is " << (unsigned int) opcodeStore_ -> shapeExtension - << ".\n" << logofs_flush; - #endif - } - else if (requestData[0] == X_NXInternalRenderExtension) - { - opcodeStore_ -> renderExtension = outputMessage[9]; - - #ifdef TEST - *logofs << "handleWrite: Render extension opcode for FD#" << fd_ - << " is " << (unsigned int) opcodeStore_ -> renderExtension - << ".\n" << logofs_flush; - #endif - } - } - break; - case X_QueryFont: - { - // - // Use differential compression at startup and plain - // data compression later. Check X_ListFonts message - // for an explaination. - // - - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_QueryFont); - - if (handleDecodeCached(decodeBuffer, serverCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - // Differential or plain data compression? - decodeBuffer.decodeBoolValue(value); - - if (value) - { - unsigned int numProperties; - unsigned int numCharInfos; - decodeBuffer.decodeValue(numProperties, 16, 8); - decodeBuffer.decodeValue(numCharInfos, 32, 10); - outputLength = 60 + numProperties * 8 + numCharInfos * 12; - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(numProperties, outputMessage + 46, bigEndian_); - PutULONG(numCharInfos, outputMessage + 56, bigEndian_); - handleDecodeCharInfo(decodeBuffer, outputMessage + 8); - handleDecodeCharInfo(decodeBuffer, outputMessage + 24); - decodeBuffer.decodeValue(value, 16, 9); - PutUINT(value, outputMessage + 40, bigEndian_); - decodeBuffer.decodeValue(value, 16, 9); - PutUINT(value, outputMessage + 42, bigEndian_); - decodeBuffer.decodeValue(value, 16, 9); - PutUINT(value, outputMessage + 44, bigEndian_); - decodeBuffer.decodeBoolValue(value); - outputMessage[48] = (unsigned char) value; - decodeBuffer.decodeValue(value, 8); - outputMessage[49] = (unsigned char) value; - decodeBuffer.decodeValue(value, 8); - outputMessage[50] = (unsigned char) value; - decodeBuffer.decodeBoolValue(value); - outputMessage[51] = (unsigned char) value; - decodeBuffer.decodeValue(value, 16, 9); - PutUINT(value, outputMessage + 52, bigEndian_); - decodeBuffer.decodeValue(value, 16, 9); - PutUINT(value, outputMessage + 54, bigEndian_); - unsigned char *nextDest = outputMessage + 60; - decodeBuffer.decodeBoolValue(value); - - int end = 0; - - if (value == 1) - { - unsigned int index; - decodeBuffer.decodeValue(index, 4); - unsigned int length; - const unsigned char *data; - ServerCache::queryFontFontCache.get(index, length, data); - memcpy(nextDest, data, length); - - end = 1; - } - - if (end == 0) - { - unsigned char *saveDest = nextDest; - unsigned int length = numProperties * 8 + numCharInfos * 12; - for (; numProperties; numProperties--) - { - decodeBuffer.decodeValue(value, 32, 9); - PutULONG(value, nextDest, bigEndian_); - decodeBuffer.decodeValue(value, 32, 9); - PutULONG(value, nextDest + 4, bigEndian_); - nextDest += 8; - } - for (; numCharInfos; numCharInfos--) - { - handleDecodeCharInfo(decodeBuffer, nextDest); - - nextDest += 12; - } - ServerCache::queryFontFontCache.set(length, saveDest); - } - - handleSave(messageStore, outputMessage, outputLength); - } - else - { - // Reply length. - unsigned int replyLength; - decodeBuffer.decodeValue(replyLength, 32, 16); - outputLength = 32 + (replyLength << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - - const unsigned char *compressedData = NULL; - unsigned int compressedDataSize = 0; - - int decompressed = handleDecompress(decodeBuffer, requestOpcode, messageStore -> dataOffset, - outputMessage, outputLength, compressedData, - compressedDataSize); - if (decompressed < 0) - { - return -1; - } - else if (decompressed > 0) - { - handleSave(messageStore, outputMessage, outputLength, - compressedData, compressedDataSize); - } - else - { - handleSave(messageStore, outputMessage, outputLength); - } - } - } - break; - case X_QueryPointer: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeBoolValue(value); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> queryPointerRootCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> queryPointerChildCache, 9); - PutULONG(value, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyRootXCache, 8); - serverCache_ -> motionNotifyLastRootX += value; - PutUINT(serverCache_ -> motionNotifyLastRootX, outputMessage + 16, - bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyRootYCache, 8); - serverCache_ -> motionNotifyLastRootY += value; - PutUINT(serverCache_ -> motionNotifyLastRootY, outputMessage + 18, - bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyEventXCache, 8); - PutUINT(serverCache_ -> motionNotifyLastRootX + value, - outputMessage + 20, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyEventYCache, 8); - PutUINT(serverCache_ -> motionNotifyLastRootY + value, - outputMessage + 22, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyStateCache); - PutUINT(value, outputMessage + 24, bigEndian_); - } - break; - case X_QueryTree: - { - unsigned int children; - decodeBuffer.decodeValue(children, 16, 8); - - outputLength = 32 + (children << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - - PutULONG(outputLength, outputMessage + 4, bigEndian_); - - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> queryTreeWindowCache); - - PutULONG(value, outputMessage + 8, bigEndian_); - - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> queryTreeWindowCache); - - PutULONG(value, outputMessage + 12, bigEndian_); - - unsigned char *next = outputMessage + 32; - - PutUINT(children, outputMessage + 16, bigEndian_); - - for (unsigned int i = 0; i < children; i++) - { - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> queryTreeWindowCache); - - PutULONG(value, next + (i * 4), bigEndian_); - } - } - break; - case X_TranslateCoords: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeBoolValue(value); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> translateCoordsChildCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> translateCoordsXCache, 8); - PutUINT(value, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> translateCoordsYCache, 8); - PutUINT(value, outputMessage + 14, bigEndian_); - } - break; - case X_GetImage: - { - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_GetImage); - - if (handleDecodeCached(decodeBuffer, serverCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - // Depth. - decodeBuffer.decodeCachedValue(cValue, 8, - serverCache_ -> depthCache); - // Reply length. - unsigned int replyLength; - decodeBuffer.decodeValue(replyLength, 32, 9); - outputLength = 32 + (replyLength << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - outputMessage[1] = (unsigned char) cValue; - // Visual. - unsigned int visual; - decodeBuffer.decodeCachedValue(visual, 29, - serverCache_ -> visualCache); - PutULONG(visual, outputMessage + 8, bigEndian_); - - // Since ProtoStep8 (#issue 108) - handleCopy(decodeBuffer, requestOpcode, messageStore -> - dataOffset, outputMessage, outputLength); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_GetPointerMapping: - { - unsigned int nextByte; - decodeBuffer.decodeValue(nextByte, 8, 4); - unsigned int replyLength; - decodeBuffer.decodeValue(replyLength, 32, 4); - outputLength = 32 + (replyLength << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - outputMessage[1] = (unsigned char) nextByte; - unsigned char *nextDest = outputMessage + 32; - for (unsigned int i = 32; i < outputLength; i++) - { - decodeBuffer.decodeValue(nextByte, 8, 4); - *nextDest++ = (unsigned char) nextByte; - } - } - break; - case X_GetKeyboardControl: - { - unsigned int nextByte; - decodeBuffer.decodeValue(nextByte, 8, 2); - unsigned int replyLength; - decodeBuffer.decodeValue(replyLength, 32, 8); - outputLength = 32 + (replyLength << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - outputMessage[1] = (unsigned char) nextByte; - unsigned char *nextDest = outputMessage + 8; - for (unsigned int i = 8; i < outputLength; i++) - { - decodeBuffer.decodeValue(nextByte, 8, 4); - *nextDest++ = (unsigned char) nextByte; - } - } - break; - default: - { - if (requestOpcode == opcodeStore_ -> getUnpackParameters) - { - #ifdef TEST - *logofs << "handleWrite: Received get unpack parameters reply " - << "OPCODE#" << (unsigned int) opcodeStore_ -> getUnpackParameters - << ".\n" << logofs_flush; - #endif - - outputLength = 32 + PACK_METHOD_LIMIT; - - outputMessage = writeBuffer_.addMessage(outputLength); - - unsigned int method; - - // - // Let agent use only the unpack methods - // implemented at both sides. - // - - for (int i = 0; i < PACK_METHOD_LIMIT; i++) - { - decodeBuffer.decodeBoolValue(method); - - control -> RemoteUnpackMethods[i] = method; - - *(outputMessage + 32 + i) = - (control -> LocalUnpackMethods[i] == 1 && - method == 1); - } - } - else if (requestOpcode == opcodeStore_ -> getShmemParameters) - { - if (handleShmemReply(decodeBuffer, requestOpcode, - outputMessage, outputLength) < 0) - { - return -1; - } - } - else if (requestOpcode == opcodeStore_ -> getFontParameters) - { - if (handleFontReply(decodeBuffer, requestOpcode, - outputMessage, outputLength) < 0) - { - return -1; - } - } - else - { - #ifdef PANIC - *logofs << "handleWrite: PANIC! No matching request for " - << "reply with sequence number " << sequenceNum - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": No matching request for " - << "reply with sequence number " << sequenceNum - << ".\n"; - - return -1; - } - } - } - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleWrite: Handled reply to OPCODE#" - << (unsigned) requestOpcode << " (" << DumpOpcode(requestOpcode) - << ")" << " for FD#" << fd_ << " with sequence " << serverSequence_ - << ". Output size is " << outputLength << ".\n" << logofs_flush; - #endif - - statistics -> addRepliedRequest(requestOpcode); - } - else // End of if (sequenceQueue_.peek() && ...) - { - // - // Reply didn't match any request opcode. - // Check again if differential encoding - // is disabled. - // - - #ifdef DEBUG - *logofs << "handleWrite: Identified generic reply.\n" - << logofs_flush; - #endif - - requestOpcode = X_Reply; - - if (control -> RemoteDeltaCompression == 0) - { - int result = handleFastWriteReply(decodeBuffer, requestOpcode, - outputMessage, outputLength); - if (result < 0) - { - return -1; - } - else if (result > 0) - { - continue; - } - } - - // - // All replies whose opcode is not pushed in - // sequence number queue are cached together. - // Among such replies are those to extension - // requests. - // - - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_NXInternalGenericReply); - - handleDecode(decodeBuffer, serverCache_, messageStore, - requestOpcode, outputMessage, outputLength); - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleWrite: Handled generic reply for FD#" << fd_ - << " with sequence " << serverSequence_ << ". Output size is " - << outputLength << ".\n" << logofs_flush; - #endif - - statistics -> addRepliedRequest(requestOpcode); - - } // End of if (sequenceQueue_.peek() && ...) else ... - - // - // If any output was produced then write opcode, - // sequence number and size to the buffer. - // - - if (outputLength > 0) - { - *outputMessage = outputOpcode; - - PutUINT(serverSequence_, outputMessage + 2, bigEndian_); - - PutULONG((outputLength - 32) >> 2, outputMessage + 4, bigEndian_); - } - - } // End of if (outputOpcode == 1)... - else - { - // - // It's an event or error. - // - - unsigned int sequenceNum; - unsigned int sequenceDiff; - - decodeBuffer.decodeCachedValue(sequenceDiff, 16, - serverCache_ -> eventSequenceCache, 7); - - sequenceNum = (serverSequence_ + sequenceDiff) & 0xffff; - - serverSequence_ = sequenceNum; - - #ifdef DEBUG - *logofs << "handleWrite: Last server sequence number for FD#" - << fd_ << " is " << serverSequence_ << " with " - << "difference " << sequenceDiff << ".\n" - << logofs_flush; - #endif - - // - // Check if this is an error that matches - // a sequence number for which we were - // expecting a reply. - // - - if (outputOpcode == X_Error) - { - unsigned short int errorSequenceNum; - unsigned char errorOpcode; - - if (sequenceQueue_.peek(errorSequenceNum, errorOpcode) && - ((unsigned) errorSequenceNum == serverSequence_)) - { - // - // Remove the queued sequence of the reply. - // - - #ifdef TEST - *logofs << "handleWrite: WARNING! Removing reply to OPCODE#" - << (unsigned) errorOpcode << " sequence " - << errorSequenceNum << " for FD#" << fd_ - << " due to error.\n" << logofs_flush; - #endif - - sequenceQueue_.pop(errorSequenceNum, errorOpcode); - - // - // Send to the client the current sequence - // number, not the number that matched the - // reply. Because we are generating replies - // at our side, Xlib can incur in a sequence - // lost if the error comes after the auto- - // generated reply. - // - - if (control -> SessionMode == session_proxy) - { - #ifdef TEST - *logofs << "handleWrite: Updating last event's sequence " - << lastSequence_ << " to X server's error sequence " - << "number " << serverSequence_ << " for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - lastSequence_ = serverSequence_; - } - } - - // - // In case of errors always send to client the - // original X server's sequence associated to - // the failing request. - // - - if (control -> SessionMode != session_proxy) - { - #ifdef TEST - *logofs << "handleWrite: Updating last event's sequence " - << lastSequence_ << " to X server's error sequence " - << "number " << serverSequence_ << " for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - lastSequence_ = serverSequence_; - } - } - - // - // Check if by producing events at client side we - // have modified the events' sequence numbering. - // In this case taint the original sequence to - // comply with the last one known by client. - // - -/* -FIXME: Recover the sequence number if the proxy - is not connected to an agent. -*/ - if (serverSequence_ > lastSequence_ || - control -> SessionMode != session_proxy) - { - #ifdef DEBUG - *logofs << "handleWrite: Updating last event's sequence " - << lastSequence_ << " to X server's sequence number " - << serverSequence_ << " for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - lastSequence_ = serverSequence_; - } - #ifdef DEBUG - else if (serverSequence_ < lastSequence_) - { - // - // Use our last auto-generated sequence. - // - - *logofs << "handleWrite: Tainting sequence number " - << serverSequence_ << " to last event's sequence " - << lastSequence_ << " for FD#" << fd_ << ".\n" - << logofs_flush; - } - #endif - - // - // Check if remote side used fast encoding. - // - - if (control -> RemoteDeltaCompression == 0) - { - int result = handleFastWriteEvent(decodeBuffer, outputOpcode, - outputMessage, outputLength); - if (result < 0) - { - return -1; - } - else if (result > 0) - { - continue; - } - } - - // - // Make space for message in the outgoing buffer - // and write opcode and sequence number. - // - - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - - *outputMessage = outputOpcode; - - PutUINT(lastSequence_, outputMessage + 2, bigEndian_); - - #ifdef DEBUG - *logofs << "handleWrite: Going to handle event or error OPCODE#" - << (unsigned int) outputOpcode << " for FD#" << fd_ - << " sequence " << lastSequence_ << " (real was " - << serverSequence_ << ").\n" << logofs_flush; - #endif - - switch (outputOpcode) - { - case X_Error: - { - unsigned char code; - decodeBuffer.decodeCachedValue(code, 8, - serverCache_ -> errorCodeCache); - outputMessage[1] = code; - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleWrite: Handled error ERR_CODE#" - << (unsigned int) code << " for FD#" << fd_; - #endif - - if ((code != 11) && (code != 8) && - (code != 15) && (code != 1)) - { - decodeBuffer.decodeValue(value, 32, 16); - PutULONG(value, outputMessage + 4, bigEndian_); - - #if defined(TEST) || defined(OPCODES) - *logofs << " RES_ID#" << value; - #endif - } - - if (code >= 18) - { - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> errorMinorCache); - PutUINT(value, outputMessage + 8, bigEndian_); - - #if defined(TEST) || defined(OPCODES) - *logofs << " MIN_OP#" << value; - #endif - } - - decodeBuffer.decodeCachedValue(cValue, 8, - serverCache_ -> errorMajorCache); - outputMessage[10] = cValue; - - #if defined(TEST) || defined(OPCODES) - *logofs << " MAJ_OP#" << (unsigned int) cValue; - #endif - - if (code >= 18) - { - unsigned char *nextDest = outputMessage + 11; - for (unsigned int i = 11; i < 32; i++) - { - decodeBuffer.decodeValue(value, 8); - *nextDest++ = (unsigned char) cValue; - } - } - - #if defined(TEST) || defined(OPCODES) - *logofs << " sequence " << lastSequence_ << " (real was " - << serverSequence_ << ") . Size is " - << (unsigned int) outputLength << ".\n" - << logofs_flush; - #endif - } - break; - case ButtonPress: - case ButtonRelease: - case KeyPress: - case KeyRelease: - case MotionNotify: - case EnterNotify: - case LeaveNotify: - { - if (outputOpcode == MotionNotify) - { - decodeBuffer.decodeBoolValue(value); - } - else if (outputOpcode == EnterNotify || outputOpcode == LeaveNotify) - { - decodeBuffer.decodeValue(value, 3); - } - else if (outputOpcode == KeyRelease) - { - decodeBuffer.decodeBoolValue(value); - if (value) - { - value = serverCache_ -> keyPressLastKey; - } - else - { - decodeBuffer.decodeValue(value, 8); - } - } - else if (outputOpcode == ButtonPress || outputOpcode == ButtonRelease) - { - decodeBuffer.decodeCachedValue(cValue, 8, - serverCache_ -> buttonCache); - value = (unsigned int) cValue; - } - else - { - decodeBuffer.decodeValue(value, 8); - } - - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeCachedValue(value, 32, - serverCache_ -> motionNotifyTimestampCache, 9); - serverCache_ -> lastTimestamp += value; - PutULONG(serverCache_ -> lastTimestamp, outputMessage + 4, - bigEndian_); - unsigned char *nextDest = outputMessage + 8; - int skipRest = 0; - if (outputOpcode == KeyRelease) - { - decodeBuffer.decodeBoolValue(value); - if (value) - { - for (unsigned int i = 0; i < 23; i++) - { - *nextDest++ = serverCache_ -> keyPressCache[i]; - } - skipRest = 1; - } - } - - if (!skipRest) - { - for (unsigned int i = 0; i < 3; i++) - { - decodeBuffer.decodeCachedValue(value, 29, - *serverCache_ -> motionNotifyWindowCache[i], 6); - PutULONG(value, nextDest, bigEndian_); - nextDest += 4; - } - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyRootXCache, 6); - serverCache_ -> motionNotifyLastRootX += value; - PutUINT(serverCache_ -> motionNotifyLastRootX, outputMessage + 20, - bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyRootYCache, 6); - serverCache_ -> motionNotifyLastRootY += value; - PutUINT(serverCache_ -> motionNotifyLastRootY, outputMessage + 22, - bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyEventXCache, 6); - PutUINT(serverCache_ -> motionNotifyLastRootX + value, - outputMessage + 24, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyEventYCache, 6); - PutUINT(serverCache_ -> motionNotifyLastRootY + value, - outputMessage + 26, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> motionNotifyStateCache); - PutUINT(value, outputMessage + 28, bigEndian_); - if (outputOpcode == EnterNotify || outputOpcode == LeaveNotify) - { - decodeBuffer.decodeValue(value, 2); - } - else - { - decodeBuffer.decodeBoolValue(value); - } - outputMessage[30] = (unsigned char) value; - if (outputOpcode == EnterNotify || outputOpcode == LeaveNotify) - { - decodeBuffer.decodeValue(value, 2); - outputMessage[31] = (unsigned char) value; - } - else if (outputOpcode == KeyPress) - { - serverCache_ -> keyPressLastKey = outputMessage[1]; - for (unsigned int i = 8; i < 31; i++) - { - serverCache_ -> keyPressCache[i - 8] = outputMessage[i]; - } - } - } - } - break; - case ColormapNotify: - { - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> colormapNotifyWindowCache, 8); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> colormapNotifyColormapCache, 8); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeBoolValue(value); - outputMessage[12] = (unsigned char) value; - decodeBuffer.decodeBoolValue(value); - outputMessage[13] = (unsigned char) value; - } - break; - case ConfigureNotify: - { - unsigned char *nextDest = outputMessage + 4; - for (unsigned int i = 0; i < 3; i++) - { - decodeBuffer.decodeCachedValue(value, 29, - *serverCache_ -> configureNotifyWindowCache[i], 9); - PutULONG(value, nextDest, bigEndian_); - nextDest += 4; - } - for (unsigned int j = 0; j < 5; j++) - { - decodeBuffer.decodeCachedValue(value, 16, - *serverCache_ -> configureNotifyGeomCache[j], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - decodeBuffer.decodeBoolValue(value); - *nextDest = value; - } - break; - case CreateNotify: - { - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> createNotifyWindowCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeValue(value, 29, 5); - serverCache_ -> createNotifyLastWindow += value; - serverCache_ -> createNotifyLastWindow &= 0x1fffffff; - PutULONG(serverCache_ -> createNotifyLastWindow, outputMessage + 8, - bigEndian_); - unsigned char* nextDest = outputMessage + 12; - for (unsigned int i = 0; i < 5; i++) - { - decodeBuffer.decodeValue(value, 16, 9); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - decodeBuffer.decodeBoolValue(value); - *nextDest = (unsigned char) value; - } - break; - case Expose: - { - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> exposeWindowCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned char *nextDest = outputMessage + 8; - for (unsigned int i = 0; i < 5; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *serverCache_ -> exposeGeomCache[i], 6); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - } - break; - case FocusIn: - case FocusOut: - { - decodeBuffer.decodeValue(value, 3); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> focusInWindowCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeValue(value, 2); - outputMessage[8] = (unsigned char) value; - } - break; - case KeymapNotify: - { - decodeBuffer.decodeBoolValue(value); - if (value) - memcpy(outputMessage + 1, ServerCache::lastKeymap.getData(), 31); - else - { - unsigned char *nextDest = outputMessage + 1; - for (unsigned int i = 1; i < 32; i++) - { - decodeBuffer.decodeValue(value, 8); - *nextDest++ = (unsigned char) value; - } - ServerCache::lastKeymap.set(31, outputMessage + 1); - } - } - break; - case MapNotify: - case UnmapNotify: - case DestroyNotify: - { - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> mapNotifyEventCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> mapNotifyWindowCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - if (outputOpcode == MapNotify || outputOpcode == UnmapNotify) - { - decodeBuffer.decodeBoolValue(value); - outputMessage[12] = (unsigned char) value; - } - } - break; - case NoExpose: - { - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> noExposeDrawableCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - serverCache_ -> noExposeMinorCache); - PutUINT(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(cValue, 8, - serverCache_ -> noExposeMajorCache); - outputMessage[10] = cValue; - } - break; - case PropertyNotify: - { - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> propertyNotifyWindowCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> propertyNotifyAtomCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeValue(value, 32, 9); - serverCache_ -> lastTimestamp += value; - PutULONG(serverCache_ -> lastTimestamp, outputMessage + 12, - bigEndian_); - decodeBuffer.decodeBoolValue(value); - outputMessage[16] = (unsigned char) value; - } - break; - case ReparentNotify: - { - unsigned char* nextDest = outputMessage + 4; - for (unsigned int i = 0; i < 3; i++) - { - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> reparentNotifyWindowCache, 9); - PutULONG(value, nextDest, bigEndian_); - nextDest += 4; - } - decodeBuffer.decodeValue(value, 16, 6); - PutUINT(value, nextDest, bigEndian_); - decodeBuffer.decodeValue(value, 16, 6); - PutUINT(value, nextDest + 2, bigEndian_); - decodeBuffer.decodeBoolValue(value); - outputMessage[20] = (unsigned char)value; - } - break; - case SelectionClear: - { - decodeBuffer.decodeValue(value, 32, 9); - serverCache_ -> lastTimestamp += value; - PutULONG(serverCache_ -> lastTimestamp, outputMessage + 4, - bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> selectionClearWindowCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> selectionClearAtomCache, 9); - PutULONG(value, outputMessage + 12, bigEndian_); - } - break; - case SelectionRequest: - { - decodeBuffer.decodeValue(value, 32, 9); - serverCache_ -> lastTimestamp += value; - PutULONG(serverCache_ -> lastTimestamp, outputMessage + 4, - bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> selectionClearWindowCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> selectionClearWindowCache, 9); - PutULONG(value, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> selectionClearAtomCache, 9); - PutULONG(value, outputMessage + 16, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> selectionClearAtomCache, 9); - PutULONG(value, outputMessage + 20, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> selectionClearAtomCache, 9); - PutULONG(value, outputMessage + 24, bigEndian_); - } - break; - case VisibilityNotify: - { - decodeBuffer.decodeCachedValue(value, 29, - serverCache_ -> visibilityNotifyWindowCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeValue(value, 2); - outputMessage[8] = (unsigned char) value; - } - break; - default: - { - #ifdef TEST - *logofs << "handleWrite: Using generic event compression " - << "for OPCODE#" << (unsigned int) outputOpcode - << ".\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(*(outputMessage + 1), 8, - serverCache_ -> genericEventCharCache); - - for (unsigned int i = 0; i < 14; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *serverCache_ -> genericEventIntCache[i]); - - PutUINT(value, outputMessage + i * 2 + 4, bigEndian_); - } - } - } // End of switch (outputOpcode)... - - #if defined(TEST) || defined(OPCODES) - if (outputOpcode != X_Error) - { - *logofs << "handleWrite: Handled event OPCODE#" - << (unsigned int) outputOpcode << " for FD#" - << fd_ << " sequence " << lastSequence_ << " (real was " - << serverSequence_ << "). Size is " << outputLength - << ".\n" << logofs_flush; - } - #endif - - // - // Check if we need to suppress the error. - // - - if (outputOpcode == X_Error && - handleTaintSyncError(*(outputMessage + 10)) > 0) - { - #if defined(TEST) || defined(OPCODES) - *logofs << "handleWrite: WARNING! Suppressed error OPCODE#" - << (unsigned int) outputOpcode << " for FD#" - << fd_ << " sequence " << lastSequence_ << ".\n" - << logofs_flush; - #endif - - writeBuffer_.removeMessage(32); - } - - } // End of if (outputOpcode == 1)... else ... - - // - // Check if we produced enough data. We need to - // decode all provided messages. Just update the - // finish flag in case of failure. - // - - handleFlush(flush_if_needed); - - } // End of while (decodeBuffer.decodeOpcodeValue(outputOpcode, 8, ... - - } // End of the decoding block. - - // - // Write any remaining data to the X connection. - // - - if (handleFlush(flush_if_any) < 0) - { - return -1; - } - - return 1; -} - -// -// End of handleWrite(). -// - -// -// Other members. -// - -int ClientChannel::handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, - T_store_action action, int position, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - #if defined(TEST) || defined(SPLIT) - - // Since ProtoStep8 (#issue 108) - *logofs << "handleSplit: PANIC! SPLIT! Split should " - << "not be enabled for message " << "OPCODE#" - << (unsigned int) store -> opcode() << ".\n" - << logofs_flush; - - HandleCleanup(); - - #endif - - // - // Refuse the split if it is not introduced - // by a start split. - // - - // Since ProtoStep7 (#issue 108) - if (splitState_.resource == nothing || enableSplit_ == 0) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Nothing to do for message " - << "OPCODE#" << (unsigned int) store -> opcode() - << " of size " << size << " position " << position - << " with action [" << DumpAction(action) << "] at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeBoolValue(0); - - return 0; - } - - // - // It's not advisable to allocate the store at - // the time we receive the start-split because - // we may process all the splits received and - // deallocate the store even before we receive - // the end split. Another message for the same - // split sequence may then come and we would - // have a null split store. - // - - handleSplitStoreAlloc(&splitResources_, splitState_.resource); - - // - // Check if the split was actually requested by - // the agent and if the request was saved in the - // message store. The split can also be refused - // if the message is smaller than the threshold - // or if the split store is already full. - // - - if (mustSplitMessage(splitState_.resource) == 0) - { - if (action == IS_HIT || canSplitMessage(splitState_.mode, size) == 0) - { - #if defined(TEST) || defined(SPLIT) - - if (splitState_.mode == split_none) - { - #ifdef PANIC - *logofs << "handleSplit: PANIC! SPLIT! Split state has " - << "mode 'none'.\n" << logofs_flush; - #endif - - HandleCleanup(); - } - - if (action != IS_HIT && (int) size >= - control -> SplitDataThreshold) - { - #ifdef WARNING - *logofs << "handleSplit: WARNING! SPLIT! Split stores have " - << clientStore_ -> getSplitTotalSize() << " messages " - << "and " << clientStore_ -> getSplitTotalStorageSize() - << " allocated bytes.\n" << logofs_flush; - #endif - } - - #endif - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Message OPCODE#" - << (unsigned int) store -> opcode() << " of size " << size - << " [not split] with resource " << splitState_.resource - << " mode " << splitState_.mode << " position " << position - << " and action [" << DumpAction(action) << "] at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeBoolValue(0); - - return 0; - } - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Message OPCODE#" - << (unsigned int) store -> opcode() << " of size " << size - << " [split] with resource " << splitState_.resource - << " mode " << splitState_.mode << " position " << position - << " and action [" << DumpAction(action) << "] at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeBoolValue(1); - - T_checksum checksum = NULL; - - if (action == IS_ADDED) - { - checksum = store -> getChecksum(position); - } - else if (action == is_discarded) - { - // - // Generate the checksum on the fly. - // - - checksum = store -> getChecksum(buffer, size, bigEndian_); - } - - // - // The method must abort the connection - // if it can't allocate the split. - // - - Split *splitMessage = clientStore_ -> getSplitStore(splitState_.resource) -> - add(store, splitState_.resource, splitState_.mode, - position, action, checksum, buffer, size); - - // - // Send the checksum. By using the checksum, - // the remote end will try to locate the - // message and load it from disk. - // - - if (action == IS_HIT) - { - splitMessage -> setState(split_loaded); - } - else if (handleSplitChecksum(encodeBuffer, checksum) == 0) - { - // - // If the checksum is not sent, for example - // because loading of messages from disk is - // disabled, then mark the split as missed. - // - - #ifdef WARNING - *logofs << "handleSplit: WARNING! Checksum not sent. " - << "Marking the split as [missed].\n" - << logofs_flush; - #endif - - splitMessage -> setState(split_missed); - } - - if (action == is_discarded) - { - delete [] checksum; - } - - // - // Check if we are ready to send a new split - // for this store. - // - - handleSplitPending(splitState_.resource); - - #if defined(TEST) || defined(SPLIT) - - *logofs << "handleSplit: SPLIT! There are " << clientStore_ -> - getSplitTotalSize() << " messages and " << clientStore_ -> - getSplitTotalStorageSize() << " bytes to send in " - << "the split stores.\n" << logofs_flush; - - clientStore_ -> dumpSplitStore(splitState_.resource); - - #endif - - return 1; -} - -int ClientChannel::handleSplit(EncodeBuffer &encodeBuffer) -{ - // - // Determine the maximum amount of bytes - // we can write in this iteration. - // - - int total = control -> SplitDataPacketLimit; - - int bytes = total; - int splits = 0; - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Handling splits " - << "for FD#" << fd_ << " with " << clientStore_ -> - getSplitTotalSize() << " elements and " << total - << " bytes to write at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - if (proxy -> handleAsyncSwitch(fd_) < 0) - { - return -1; - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Looping to find " - << "if there is any split to send.\n" - << logofs_flush; - #endif - - SplitStore *splitStore; - - Split *splitMessage; - - // - // Divide the available bandwidth among all the active - // split stores by implementing a simple round-robin - // mechanism. This can be extended by using an external - // function returning the number of bytes to be written - // based on the state of the split (splits which didn't - // receive yet a confirmation event could be delayed), - // the current bitrate, and by letting the agent asso- - // ciate a priority to the resource in the start split - // operation. - // - - splitState_.pending = 0; - - splitResources_.rotate(); - - // - // Copy the list since elements can be removed - // in the middle of the loop. - // - - T_list splitList = splitResources_.copyList(); - - for (T_list::iterator j = splitList.begin(); - j != splitList.end(); j++) - { - int resource = *j; - - #ifdef DEBUG - *logofs << "handleSplit: SPLIT! Looping with current " - << "resource " << resource << ".\n" - << logofs_flush; - #endif - - splitStore = clientStore_ -> getSplitStore(resource); - - if (splitStore != NULL) - { - // - // Don't send more than the the packet size - // bytes but ensure that we abort any split - // found in the disk cache. - // - - for (;;) - { - #if defined(TEST) || defined(SPLIT) - - clientStore_ -> dumpSplitStore(resource); - - #endif - - splitMessage = splitStore -> getFirstSplit(); - - if (splitMessage == NULL) - { - // - // We have created the store after a start - // split but no message was added yet. - // - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: WARNING! SPLIT! The split store " - << "is still empty.\n" << logofs_flush; - #endif - - break; - } - - // - // Splits already aborted can't be in the - // split store. - // - - #if defined(TEST) || defined(SPLIT) - - if (splitMessage -> getState() == split_aborted) - { - *logofs << "handleSplit: PANIC! SPLIT! Found an " - << "aborted split in store [" << resource - << "].\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - // - // Check if there are more messages in the - // store that can be aborted or if we have - // exceeded the number of bytes we can send - // for this iteration. - // - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Checking closure " - << "of the inner loop with " << bytes - << " bytes to write and split state [" - << DumpState(splitMessage -> getState()) - << "].\n" << logofs_flush; - #endif - - if ((splitMessage -> getMode() == split_sync && - splitMessage -> getState() == split_added) || - (bytes <= 0 && splitMessage -> - getState() != split_loaded)) - { - break; - } - - // - // If the split was loaded at the remote - // side abort it immediately. - // - - if (splitMessage -> getState() == split_loaded) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Sending more data " - << "for store [" << resource << "] with " - << "a split to be aborted.\n" - << logofs_flush; - #endif - - if (handleSplitSend(encodeBuffer, resource, splits, bytes) < 0) - { - return -1; - } - } - else if (bytes > 0) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Sending more data " - << "for store [" << resource << "] with " - << bytes << " bytes to send.\n" - << logofs_flush; - #endif - - if (handleSplitSend(encodeBuffer, resource, splits, bytes) < 0) - { - return -1; - } - } - - // - // Check if the split store was deleted. - // - - splitStore = clientStore_ -> getSplitStore(resource); - - if (splitStore == NULL) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Exiting from the " - << "inner loop with split store [" << resource - << "] destroyed.\n" << logofs_flush; - #endif - - break; - } - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Completed handling splits " - << "for store [" << resource << "] with " << bytes - << " bytes still to send.\n" << logofs_flush; - #endif - - // - // Check if there is still a split to - // send for the store just processed. - // - - handleSplitPending(resource); - } - } - - #if defined(TEST) || defined(SPLIT) - - if (splits == 0) - { - #ifdef PANIC - *logofs << "handleSplit: PANIC! Function called but " - << "no split message was sent.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - - *logofs << "handleSplit: SPLIT! Sent " << splits - << " splits and " << total - bytes << " bytes for FD#" << fd_ - << " with " << clientStore_ -> getSplitTotalStorageSize() - << " bytes and [" << clientStore_ -> getSplitTotalSize() - << "] splits remaining.\n" << logofs_flush; - - *logofs << "handleSplit: SPLIT! The pending split flag is " - << splitState_.pending << " with " << clientStore_ -> - getSplitTotalSize() << " splits in the split stores.\n" - << logofs_flush; - - clientStore_ -> dumpSplitStores(); - - #endif - - return 1; -} - -int ClientChannel::handleSplitSend(EncodeBuffer &encodeBuffer, int resource, - int &splits, int &bytes) -{ - #if defined(TEST) || defined(SPLIT) - - SplitStore *splitStore = clientStore_ -> getSplitStore(resource); - - Split *splitMessage = splitStore -> getFirstSplit(); - - if (splitStore -> getResource() != resource || - splitMessage -> getResource() != resource) - { - #ifdef PANIC - *logofs << "handleSplitSend: PANIC! The resource doesn't " - << "match the split store.\n" << logofs_flush; - #endif - - HandleCleanup(); - } - - *logofs << "handleSplitSend: SPLIT! Sending message " - << "OPCODE#" << (unsigned) opcodeStore_ -> splitData - << " for resource " << splitMessage -> getResource() - << " with request " << splitMessage -> getRequest() - << " position " << splitMessage -> getPosition() - << " and " << bytes << " bytes to write.\n" - << logofs_flush; - #endif - - // - // Use a special opcode to signal the other - // side this is part of a split and not a - // new message. - // - - encodeBuffer.encodeOpcodeValue(opcodeStore_ -> splitData, - clientCache_ -> opcodeCache); - - encodeBuffer.encodeCachedValue(resource, 8, - clientCache_ -> resourceCache); - - int result = clientStore_ -> getSplitStore(resource) -> - send(encodeBuffer, bytes); - - if (result < 0) - { - #ifdef PANIC - *logofs << "handleSplit: PANIC! Error sending splits for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Error sending splits for FD#" - << fd_ << ".\n"; - - return -1; - } - - // - // Get the bits written and update the - // statistics for this special opcode. - // - - int bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(SPLIT)|| defined(OPCODES) - *logofs << "handleSplitSend: SPLIT! Handled request OPCODE#" - << (unsigned int) opcodeStore_ -> splitData << " (" - << DumpOpcode(opcodeStore_ -> splitData) << ")" << " for FD#" - << fd_ << " sequence none. 0 bytes in, " << bits << " bits (" - << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; - #endif - - statistics -> addRequestBits(opcodeStore_ -> splitData, 0, bits); - - bytes -= bits >> 3; - - splits++; - - if (result == 1) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitSend: SPLIT! Split at the head " - << "of the list was completely transferred.\n" - << logofs_flush; - #endif - - // - // The split at the head of the list was - // completely transferred. - // - - handleRestart(sequence_deferred, resource); - } - #if defined(TEST) || defined(SPLIT) - else - { - *logofs << "handleSplitSend: SPLIT! More data to send " - << "for the split at the head of the list.\n" - << logofs_flush; - } - #endif - - return result; -} - -int ClientChannel::handleSplitChecksum(EncodeBuffer &encodeBuffer, T_checksum checksum) -{ - // - // Send the checksum only if the loading - // or the saving of the message to the - // persistent image cache is enabled. - // - - if ((control -> ImageCacheEnableLoad == 1 || - control -> ImageCacheEnableSave == 1) && - (enableLoad_ == 1 || enableSave_ == 1)) - { - encodeBuffer.encodeBoolValue(1); - - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - encodeBuffer.encodeValue((unsigned int) checksum[i], 8); - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitChecksum: SPLIT! Sent checksum " - << "[" << DumpChecksum(checksum) << "].\n" - << logofs_flush; - #endif - - return 1; - } - else - { - encodeBuffer.encodeBoolValue(0); - - return 0; - } -} - -void ClientChannel::handleSplitPending() -{ - #if defined(TEST) || defined(SPLIT) - - int previous = splitState_.pending; - - #endif - - if (clientStore_ -> getSplitTotalSize() == 0) - { - splitState_.pending = 0; - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitPending: SPLIT! Set the pending " - << "split flag to " << splitState_.pending - << " with split stores empty.\n" - << logofs_flush; - #endif - } - else - { - // - // Loop through the stores to find if - // there is any split that has become - // ready. - // - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitPending: WARNING! SPLIT! Looping to " - << "find if there is any split pending.\n" - << logofs_flush; - #endif - - splitState_.pending = 0; - - T_list &splitList = splitResources_.getList(); - - for (T_list::iterator j = splitList.begin(); - j != splitList.end(); j++) - { - int resource = *j; - - SplitStore *splitStore = clientStore_ -> getSplitStore(resource); - - if (splitStore != NULL) - { - #if defined(TEST) || defined(SPLIT) - - clientStore_ -> dumpSplitStore(resource); - - #endif - - Split *splitMessage = splitStore -> getFirstSplit(); - - if (splitMessage != NULL && canSendSplit(splitMessage) == 1) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitPending: SPLIT! Found a pending " - << "split in store [" << resource << "].\n" - << logofs_flush; - #endif - - splitState_.pending = 1; - - #if defined(TEST) || defined(SPLIT) - - if (splitMessage -> getState() == split_loaded) - { - *logofs << "handleSplitPending: PANIC! SPLIT! Found a " - << "loaded split in store [" << resource - << "].\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - break; - } - } - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitPending: SPLIT! Set the pending " - << "split flag to " << splitState_.pending - << " with " << clientStore_ -> getSplitTotalSize() - << " splits in the split stores.\n" - << logofs_flush; - #endif - } - - #if defined(TEST) || defined(SPLIT) - - if (splitState_.pending != previous) - { - *logofs << "handleSplitPending: SPLIT! Pending state " - << "changed from " << previous << " to " - << splitState_.pending << ".\n" - << logofs_flush; - } - - #endif -} - -int ClientChannel::handleSplitEvent(EncodeBuffer &encodeBuffer, Split *splitMessage) -{ - SplitStore *splitStore; - - int resource = splitMessage -> getResource(); - - #if defined(TEST) || defined(INFO) - - splitStore = clientStore_ -> getSplitStore(resource); - - if (splitStore == NULL) - { - #ifdef PANIC - *logofs << "handleSplitEvent: PANIC! The split store can't " - << "be NULL handling abort splits.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - else if (splitMessage -> getState() != split_loaded) - { - *logofs << "handleSplitEvent: PANIC! Can't find the split " - << "to be aborted.\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - // - // Send any split that it is possible to - // abort until the store is either empty - // or the next split can't be aborted. - // - - if (proxy -> handleAsyncSwitch(fd_) < 0) - { - return -1; - } - - while ((splitStore = clientStore_ -> - getSplitStore(resource)) != NULL && - (splitMessage = splitStore -> getFirstSplit()) != NULL && - splitMessage -> getState() == split_loaded) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitEvent: SPLIT! Aborting split with " - << "checksum [" << DumpChecksum(splitMessage -> - getChecksum()) << "] for resource " << resource - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - int any = 0; - - if (handleSplitSend(encodeBuffer, resource, any, any) < 0) - { - return -1; - } - } - - #if defined(TEST) || defined(SPLIT) - - if ((splitStore = clientStore_ -> - getSplitStore(resource)) == NULL) - { - *logofs << "handleSplitEvent: SPLIT! The split store [" - << resource << "] has been destroyed.\n" - << logofs_flush; - } - else if ((splitMessage = splitStore -> - getFirstSplit()) == NULL) - { - *logofs << "handleSplitEvent: SPLIT! The split store [" - << resource << "] is empty.\n" - << logofs_flush; - } - else if (splitMessage -> getState() != split_loaded) - { - *logofs << "handleSplitEvent: SPLIT! The split at the " - << "head of store [" << resource << "] doesn't " - << "need to be aborted.\n" << logofs_flush; - } - - #endif - - return 1; -} - -int ClientChannel::handleSplitEvent(DecodeBuffer &decodeBuffer) -{ - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitEvent: SPLIT! Handling abort " - << "split messages for FD#" << fd_ << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - // Since ProtoStep7 (#issue 108) - - // - // Decode the information about the - // message to be updated. - // - - unsigned char resource; - - decodeBuffer.decodeCachedValue(resource, 8, - serverCache_ -> resourceCache); - - unsigned int loaded; - - decodeBuffer.decodeBoolValue(loaded); - - unsigned char request; - unsigned int size; - - if (loaded == 1) - { - decodeBuffer.decodeOpcodeValue(request, serverCache_ -> abortOpcodeCache); - - decodeBuffer.decodeValue(size, 32, 14); - } - else - { - request = 0; - size = 0; - } - - unsigned int value; - - md5_byte_t checksum[MD5_LENGTH]; - - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - decodeBuffer.decodeValue(value, 8); - - checksum[i] = (unsigned char) value; - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitEvent: SPLIT! Checking split " - << "with checksum [" << DumpChecksum(checksum) - << "] loaded " << loaded << " request " << (unsigned int) - request << " compressed size " << size << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - Split *splitMessage = handleSplitFind(checksum, resource); - - if (splitMessage != NULL) - { - if (loaded == 1) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitEvent: SPLIT! Marked split with " - << "checksum [" << DumpChecksum(checksum) << "] " - << "as [loaded] at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - splitMessage -> setState(split_loaded); - - #if defined(TEST) || defined(SPLIT) - - if (splitMessage -> compressedSize() != (int) size) - { - *logofs << "handleSplitEvent: WARNING! SPLIT! Updating " - << "compressed data size from " << splitMessage -> - compressedSize() << " to " << size << ".\n" - << logofs_flush; - } - - #endif - - splitMessage -> compressedSize(size); - - // - // The splits to be aborted are checked by the split - // store at the time we are going to send a new chunk - // of split data. The splits must be strictly handled - // in the same order as they were added to the split - // store and the split we want to abort here may be - // not at the head of the list. - // - - if (splitMessage == clientStore_ -> - getSplitStore(resource) -> getFirstSplit()) - { - // - // We don't need to flush this packet immediately. - // The abort can be sent at any time to the remote - // proxy. What's important is that we restart the - // agent resource as soon as possible. - // - - #if defined(TEST) || defined(SPLIT) - - T_timestamp startTs = getTimestamp(); - - *logofs << "handleSplitEvent: SPLIT! Encoding abort " - << "split events for FD#" << fd_ << " with " - << "resource " << (unsigned) resource << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - if (proxy -> handleAsyncSplit(fd_, splitMessage) < 0) - { - return -1; - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitEvent: SPLIT! Spent " - << diffTimestamp(startTs, getTimestamp()) << " Ms " - << "handling abort split events for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - // - // Check if we can clear the pending flag. - // - - handleSplitPending(); - } - #if defined(TEST) || defined(SPLIT) - else - { - *logofs << "handleSplitEvent: WARNING! SPLIT! Abort split " - << "event not sent because not at the head " - << "of the list.\n" << logofs_flush; - } - #endif - } - else - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitEvent: SPLIT! Marked split with " - << "checksum [" << DumpChecksum(checksum) << "] " - << "as [missed] at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - splitMessage -> setState(split_missed); - - // - // Check if we can set the pending flag. - // - - handleSplitPending(resource); - } - } - else - { - // - // The split report came after the split was already - // sent or the split store deleted. If the message - // had been loaded from disk by the remote side, we - // need to update the compressed size in our message - // store or the checksum will not match at the time - // we will try to save the message store on disk. - // - - if (loaded == 1 && size != 0) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitEvent: WARNING! SPLIT! Can't find " - << "the split. Updating in the message store.\n" - << logofs_flush; - #endif - - MessageStore *store = clientStore_ -> getRequestStore(request); - - if (store != NULL) - { - store -> updateData(checksum, size); - } - #if defined(TEST) || defined(SPLIT) - else - { - #ifdef PANIC - *logofs << "handleSplitEvent: PANIC! The message store " - << "can't be null.\n" << logofs_flush; - #endif - - HandleCleanup(); - } - #endif - } - #if defined(TEST) || defined(SPLIT) - else - { - *logofs << "handleSplitEvent: WARNING! SPLIT! No need to " - << "update the store with loaded " << loaded - << " and compressed size " << size << ".\n" - << logofs_flush; - } - #endif - } - - return 1; -} - -Split *ClientChannel::handleSplitFind(T_checksum checksum, int resource) -{ - // - // It can be that we handled all the splits, - // restarted the resource and deleted the - // store before the event could even reach - // our side. - // - - SplitStore *splitStore = clientStore_ -> getSplitStore(resource); - - if (splitStore != NULL) - { - Split *splitMessage; - - T_splits *splitList = splitStore -> getSplits(); - - for (T_splits::iterator i = splitList -> begin(); - i != splitList -> end(); i++) - { - splitMessage = (*i); - - if (splitMessage -> getChecksum() != NULL) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitFind: SPLIT! Comparing with message [" - << DumpChecksum(splitMessage -> getChecksum()) - << "].\n" << logofs_flush; - #endif - - if (memcmp(checksum, splitMessage -> getChecksum(), MD5_LENGTH) == 0) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitFind: SPLIT! Located split for " - << "checksum [" << DumpChecksum(checksum) << "] " - << "in store [" << splitStore -> getResource() - << "].\n" << logofs_flush; - #endif - - return splitMessage; - } - } - } - } - #if defined(TEST) || defined(SPLIT) - else - { - *logofs << "handleSplitFind: WARNING! SPLIT! The split store " - << "was already deleted.\n" << logofs_flush; - } - #endif - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitFind: WARNING! SPLIT! Can't find the " - << "split for checksum [" << DumpChecksum(checksum) - << "].\n" << logofs_flush; - #endif - - return NULL; -} - -int ClientChannel::handleRestart(T_sequence_mode mode, int resource) -{ - // - // The agent must send a start-split message, followed by the - // X messages that may be optionally split by the proxy. Usu- - // ally, in the middle of a start-split/end-split sequence is - // a single PutImage() or PutPackedImage(), that, in turn, - // can generate multiple partial requests, like a SetUnpack- - // Colormap() and SetUnpackAlpha() followed by the image that - // must be transferred. Multiple requests may be also genera- - // ted because the maximum size of a X request has been exce- - // eded, so that Xlib has divided the single image in multi- - // ple sub-image requests. The agent doesn't need to take care - // of that, except tracking the result of the split operation. - // - // By monitoring the notify events sent by the proxy, the - // agent will have to implement its own strategy to deal with - // its resources (for example its clients). For example: - // - // - It will issue a new image request and suspend a client - // if the image was not entirely sent in the main X oputput - // stream. - // - // - It will choose to commit or discard the messages after - // they are recomposed at the remote side. The set of mes- - // sages that will have to be committed will include all - // messages that were part of the split (the colormap, the - // alpha channel). - // - // - It will restart its own client, in the case it had been - // suspended. - // - // A more useful strategy would be to replace the original im- - // age with a tiny 'placeholder' if a split took place, and - // synchronize the content of the drawable at later time. This - // is generally referred as 'lazy encoding'. - // - // The agent will be able to identify the original split ope- - // ration (the one marked with the start-spit) by the small - // integer number (0-255) referred to as the 'resource' field. - // - // Before the proxy will be able to report the status of the - // split, the agent will have to close the sequence by issueing - // an end-split. The proxy will then report the result of the - // operation, so that the agent will have the option of suspend- - // ing the client or marking the drawable as dirty and take - // care of synchronizing it at later time. - // - // One of the following cases may be encountered: - // - // notify_no_split: All messages were sent in the main out- - // put stream, so that no split actually - // took place. - // - // notify_start_split: One or more messages were split, so, - // at discrection of the agent, the client - // may be suspended until the transferral - // is completed. - // - // notify_commit_split: One of the requests that made up the - // split was recomposed. The agent should - // either commit the given request or tell - // the proxy to discard it. - // - // notify_end_split: The split was duly completed. The agent - // can restart the client. - // - // notify_empty_split: No more split operation are pending. - // The agent can use this information to - // implement specific strategies requiring - // that all messages have been recomposed - // at the remote end, like updating the - // drawables that were not synchronized - // because of the lazy encoding. - // - // By checking the split and commit store we can determine if we - // need to send a new notification event to the agent. There can - // be four different cases: - // - // - If the split store is not null and not empty, we are still - // in the middle of a split. - // - // - If the commit store is not empty, we completely recomposed - // a full message and can send a new commit notify. - // - // - If the split store has become empty, we recomposed all the - // messages added for the given resource, and so will be able - // to restart the resource. - // - // - If no more messages are in the split stores, we can notify - // an empty split event to the agent. - // - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleRestart: SPLIT! Handling [" - << (mode == sequence_immediate ? "immediate" : "deferred") - << "] restart events for resource " << resource << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - SplitStore *splitStore = clientStore_ -> getSplitStore(resource); - - if (mode == sequence_immediate) - { - // - // We have received an end-split request. If the store - // was not deleted already, we mark the last split added - // as the one ending the row for this resource. If the - // commit() function returns 0 it means that the split - // store is either empty or that we did not add any split - // for this resource. This is because when connected to - // an old proxy version we only have a single store for - // all the resources. - // - // It can happen that all the split messages that were - // originally appended to the list were completely sent - // before our client had the chance of ending the split - // sequence. In this case the split store will be empty - // or already deleted and so we will be able to restart - // the resource. - // - - #if defined(TEST) || defined(SPLIT) - - if (splitStore == NULL) - { - *logofs << "handleRestart: WARNING! SPLIT! Split store [" - << resource << "] was already deleted.\n" - << logofs_flush; - } - else - { - clientStore_ -> dumpSplitStore(resource); - } - - #endif - - if (splitStore == NULL || splitStore -> getSize() == 0) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleRestart: SPLIT! Immediate agent split event " - << "TYPE#" << (unsigned) opcodeStore_ -> noSplitNotify - << " [no split] with resource " << resource - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - if (handleNotify(notify_no_split, sequence_immediate, - resource, nothing, nothing) < 0) - { - return -1; - } - } - else - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleRestart: SPLIT! Immediate agent split event " - << "TYPE#" << (unsigned) opcodeStore_ -> startSplitNotify - << " [start split] with resource " << resource - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - if (handleNotify(notify_start_split, sequence_immediate, - resource, nothing, nothing) < 0) - { - return -1; - } - } - } - else - { - // - // We have completely transferred a message - // that was put in the split store. - // - // The id of the resource can be different - // than the index of the store if we are - // connected to an old proxy. - // - - #if defined(TEST) || defined(SPLIT) - - if (splitStore == NULL) - { - #ifdef PANIC - *logofs << "handleRestart: PANIC! The split store can't " - << "be NULL handling deferred restart events.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - else - { - clientStore_ -> dumpSplitStore(resource); - } - - #endif - - CommitStore *commitStore = clientStore_ -> getCommitStore(); - - #if defined(TEST) || defined(SPLIT) - - clientStore_ -> dumpCommitStore(); - - #endif - - // - // Check if there is any commit to notify. - // - - Split *split; - - T_splits *commitList = commitStore -> getSplits(); - - for (T_splits::iterator i = commitList -> begin(); - i != commitList -> end(); i++) - { - split = *i; - - if (split -> getState() != split_notified) - { - #if defined(TEST) || defined(SPLIT) - - if (split -> getResource() != resource) - { - #ifdef PANIC - *logofs << "handleSplitSend: PANIC! The resource doesn't " - << "match the split store.\n" << logofs_flush; - #endif - - HandleCleanup(); - } - - #endif - - int request = split -> getRequest(); - int position = split -> getPosition(); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleRestart: SPLIT! Deferred agent split event " - << "TYPE#" << (unsigned) opcodeStore_ -> commitSplitNotify - << " [commit split] with resource " << resource << " request " - << request << " position " << position << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - if (handleNotify(notify_commit_split, sequence_deferred, - resource, request, position) < 0) - { - return -1; - } - - // - // Don't send the notification again. - // - - split -> setState(split_notified); - } - #if defined(TEST) || defined(SPLIT) - else - { - *logofs << "handleRestart: SPLIT! Split for request " - << split -> getRequest() << " and position " - << split -> getPosition() << " was already " - << "notified.\n" << logofs_flush; - } - #endif - } - - // - // Don't send the end split if we are still - // in the middle of a start-split/end-split - // sequence. We'll send a no-split at the - // time the end-split is received. - // - - if (splitStore -> getSize() == 0 && - splitStore -> getResource() != splitState_.resource) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleRestart: SPLIT! Deferred agent split event " - << "TYPE#" << (unsigned) opcodeStore_ -> endSplitNotify - << " [end split] with resource " << resource << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - if (handleNotify(notify_end_split, sequence_deferred, - resource, nothing, nothing) < 0) - { - return -1; - } - } - #if defined(TEST) || defined(SPLIT) - else if (splitStore -> getSize() == 0 && - splitStore -> getResource() == splitState_.resource) - { - *logofs << "handleRestart: SPLIT! WARNING! The split store " - << "for resource " << resource << " was emptied in the " - << "split sequence at " << strMsTimestamp() << ".\n" - << logofs_flush; - } - #endif - } - - // - // Remove the split store if it's empty. - // - - if (splitStore != NULL && splitStore -> getSize() == 0 && - splitStore -> getResource() != splitState_.resource) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleRestart: SPLIT! Removing the split store [" - << resource << "] at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - handleSplitStoreRemove(&splitResources_, resource); - - if (clientStore_ -> getSplitTotalSize() == 0) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleRestart: SPLIT! Deferred agent split event " - << "TYPE#" << (unsigned) opcodeStore_ -> emptySplitNotify - << " [empty split] for FD#" << fd_ << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - if (handleNotify(notify_empty_split, sequence_deferred, - nothing, nothing, nothing) < 0) - { - return -1; - } - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleRestart: SPLIT! There are " << clientStore_ -> - getSplitTotalSize() << " messages and " << clientStore_ -> - getSplitTotalStorageSize() << " bytes to send in " - << "the split stores.\n" << logofs_flush; - - if ((clientStore_ -> getSplitTotalSize() != 0 && - clientStore_ -> getSplitTotalStorageSize() == 0) || - (clientStore_ -> getSplitTotalSize() == 0 && - clientStore_ -> getSplitTotalStorageSize() != 0)) - { - #ifdef PANIC - *logofs << "handleRestart: PANIC! Inconsistency detected " - << "while handling the split stores.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - - #endif - } - - return 1; -} - -int ClientChannel::handleTaintLameRequest(unsigned char &opcode, const unsigned char *&buffer, - unsigned int &size) -{ - // - // Test the efficiency of the encoding - // without these RENDER requests. - // - - if (opcode == opcodeStore_ -> renderExtension && - (*(buffer + 1) == X_RenderCompositeGlyphs8 || - *(buffer + 1) == X_RenderCompositeGlyphs16 || - *(buffer + 1) == X_RenderCompositeGlyphs32 || - *(buffer + 1) == X_RenderAddGlyphs || - *(buffer + 1) == X_RenderTrapezoids)) - { - #ifdef TEST - *logofs << "handleTaintLameRequest: Tainting request " - << "OPCODE#" << (unsigned int) opcode << " MINOR#" - << (unsigned int) *(buffer + 1) << " for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - opcode = X_NoOperation; - - return 1; - } - - return 0; -} - -int ClientChannel::handleTaintSyncRequest(unsigned char &opcode, const unsigned char *&buffer, - unsigned int &size) -{ - // - // Should short-circuit other common replies - // whose values could be queried only once. - // Examples are X_InterAtom, X_ListExtension - // and X_QueryExtension. - // - - if (taintCounter_ >= control -> TaintThreshold) - { - #ifdef DEBUG - *logofs << "handleTaintSyncRequest: Reset taint counter after " - << taintCounter_ << " replies managed.\n" - << logofs_flush; - #endif - - taintCounter_ = 0; - - return 0; - } - - // - // Check if we are rolling the counter. - // The client sequence number has not - // been incremented yet in the loop. - // - - unsigned int sequence = (clientSequence_ + 1) & 0xffff; - - #ifdef DEBUG - *logofs << "handleTaintSyncRequest: Opcode is " << (unsigned) opcode - << " expected client sequence is " << sequence - << ".\n" << logofs_flush; - #endif - - if (sequence == 0xffff) - { - return 0; - } - - unsigned short t1; - unsigned char t2; - - // - // Check if there is a previous reply - // pending. - // - - if (sequenceQueue_.peek(t1, t2) != 0) - { - #ifdef DEBUG - *logofs << "handleTaintSyncRequest: Skipping taint of reply due to " - << "pending request OPCODE#" << t1 << " with sequence " - << (unsigned int) t2 << ".\n" << logofs_flush; - #endif - - return 0; - } - - #ifdef DEBUG - *logofs << "handleTaintSyncRequest: Suppressing get input focus " - << "request for FD#" << fd_ << " with sequence " - << sequence << ".\n" << logofs_flush; - #endif - - unsigned char *reply = writeBuffer_.addMessage(32); - - *(reply + 0) = X_Reply; - - PutUINT(sequence, reply + 2, bigEndian_); - - PutULONG(0, reply + 4, bigEndian_); - - // - // Set revert-to to none. - // - - *(reply + 1) = 0; - - // - // Set focus to none. - // - - PutULONG(0, reply + 8, bigEndian_); - - // - // Save the sequence number, not incremented - // yet, we used to auto-generate this reply. - // - - lastSequence_ = clientSequence_ + 1; - - #ifdef TEST - *logofs << "handleTaintSyncRequest: Registered " << lastSequence_ - << " as last auto-generated sequence number.\n" - << logofs_flush; - #endif - - // - // Taint the request to a X_NoOperation. - // - - opcode = X_NoOperation; - - // - // We may assume that the client has finished - // drawing and flush immediately, even if this - // seems to perceively affect the performance. - // - // priority_++; - // - - if (handleFlush(flush_if_any) < 0) - { - return -1; - } - - taintCounter_++; - - return 1; -} - -int ClientChannel::handleTaintSyncError(unsigned char opcode) -{ - if (control -> TaintReplies > 0) - { - // - // By enabling short-circuiting of replies - // some window managers can get confused - // by some otherwise innocuous X errors. - // - - if (opcode == X_GrabKey || opcode == X_ReparentWindow || - opcode == X_ConfigureWindow) - { - #if defined(TEST) || defined(OPCODES) - *logofs << "handleTaintSyncError: WARNING! Suppressed error " - << "on OPCODE#" << (unsigned int) opcode << " for FD#" - << fd_ << " sequence " << lastSequence_ << " (real was " - << serverSequence_ << ").\n" << logofs_flush; - #endif - - return 1; - } - } - - return 0; -} - -int ClientChannel::handleNotify(T_notification_type type, T_sequence_mode mode, - int resource, int request, int position) -{ - if (finish_ == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleNotify: Discarding notification on " - << "channel for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - - // - // Add a new message to the write buffer. - // - - unsigned char *event = writeBuffer_.addMessage(32); - - // - // Event is ClientMessage, atom and - // window are 0, format is 32. - // - - *(event + 0) = ClientMessage; - - PutULONG(0, event + 4, bigEndian_); - PutULONG(0, event + 8, bigEndian_); - - *(event + 1) = 32; - - // - // If the event follows immediately the request (that is the - // sequence mode is 'immediate') then the sequence number is - // the one of the last request, else it should be the last - // sequence number encoded by peer proxy but, as we are ins- - // erting events in the stream, we must ensure that the se- - // quence we send is not less than the last sequence we have - // auto-generated. - // - - if (mode == sequence_immediate) - { - // - // Save the sequence number we used - // to auto-generate this event. - // - - lastSequence_ = clientSequence_; - - #if defined(TEST) || defined(INFO) - *logofs << "handleNotify: Registered " << lastSequence_ - << " as last auto-generated sequence number.\n" - << logofs_flush; - #endif - } - else - { - if (serverSequence_ > lastSequence_) - { - #ifdef DEBUG - *logofs << "handleNotify: Updating last event's sequence " - << lastSequence_ << " to X server's sequence number " - << serverSequence_ << " for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - lastSequence_ = serverSequence_; - } - #ifdef DEBUG - else if (serverSequence_ < lastSequence_) - { - // - // Use our last auto-generated sequence. - // - - *logofs << "handleNotify: Tainting sequence number " - << serverSequence_ << " to last event's sequence " - << lastSequence_ << " for FD#" << fd_ << ".\n" - << logofs_flush; - } - #endif - } - - PutUINT(lastSequence_, event + 2, bigEndian_); - - // - // Be sure we set to void the fields that - // are not significant for the specific - // notification message. - // - - PutULONG(nothing, event + 16, bigEndian_); - PutULONG(nothing, event + 20, bigEndian_); - PutULONG(nothing, event + 24, bigEndian_); - - switch (type) - { - case notify_no_split: - { - PutULONG(opcodeStore_ -> noSplitNotify, - event + 12, bigEndian_); - - PutULONG(resource, event + 16, bigEndian_); - - break; - } - case notify_start_split: - { - PutULONG(opcodeStore_ -> startSplitNotify, - event + 12, bigEndian_); - - PutULONG(resource, event + 16, bigEndian_); - - break; - } - case notify_commit_split: - { - PutULONG(opcodeStore_ -> commitSplitNotify, - event + 12, bigEndian_); - - PutULONG(resource, event + 16, bigEndian_); - - PutULONG(request, event + 20, bigEndian_); - - PutULONG(position, event + 24, bigEndian_); - - break; - } - case notify_end_split: - { - PutULONG(opcodeStore_ -> endSplitNotify, - event + 12, bigEndian_); - - PutULONG(resource, event + 16, bigEndian_); - - break; - } - case notify_empty_split: - { - PutULONG(opcodeStore_ -> emptySplitNotify, - event + 12, bigEndian_); - break; - } - default: - { - #ifdef PANIC - *logofs << "handleNotify: PANIC! Unrecognized notify " - << "TYPE#" << type << ".\n" - << logofs_flush; - #endif - - return -1; - } - } - - #if defined(TEST) || defined(INFO) || defined (SPLIT) - - *logofs << "handleNotify: Sending " - << (mode == sequence_immediate ? "immediate " : "deferred ") - << "agent notify event TYPE#" << GetULONG(event + 12, bigEndian_) - << logofs_flush; - - if (resource != nothing) - { - *logofs << " with resource " << GetULONG(event + 16, bigEndian_) - << logofs_flush; - - if (request != nothing && position != nothing) - { - *logofs << " request " << GetULONG(event + 20, bigEndian_) - << " position " << GetULONG(event + 24, bigEndian_) - << logofs_flush; - } - } - - *logofs << ".\n" << logofs_flush; - - #endif - - // - // Send the notification now. - // - - if (handleFlush(flush_if_any) < 0) - { - return -1; - } - - return 1; -} - -int ClientChannel::handleCommitSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - // - // Get the data of the request to be - // committed. - // - - unsigned char request = *(buffer + 5); - - MessageStore *store = clientStore_ -> getRequestStore(request); - - if (store == NULL) - { - #ifdef PANIC - *logofs << "handleCommitSplitRequest: PANIC! Can't commit split for " - << "request OPCODE#" << (unsigned int) request - << ". No message store found.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't commit split for request " - << "OPCODE#" << (unsigned int) request - << ". No message store found.\n"; - - return -1; - } - - // - // The position in cache of the message - // to commit. Encode it as difference in - // respect to the last encoded value. - // - - unsigned int position = GetULONG(buffer + 8, bigEndian_); - - unsigned char resource = *(buffer + 1); - unsigned int commit = *(buffer + 4); - - #if defined(TEST) || defined(SPLIT) - - if (commit == 1) - { - *logofs << "handleCommitSplitRequest: SPLIT! Committing request " - << "OPCODE#" << (unsigned) request << " at position " - << position << " for FD#" << fd_ << " with resource " - << (unsigned) resource << ".\n" << logofs_flush; - } - else - { - *logofs << "handleCommitSplitRequest: SPLIT! Discarding request " - << "OPCODE#" << (unsigned) request << " at position " - << position << " for FD#" << fd_ << " with resource " - << (unsigned) resource << ".\n" << logofs_flush; - } - - #endif - - encodeBuffer.encodeOpcodeValue(request, clientCache_ -> opcodeCache); - - int diffCommit = position - splitState_.commit; - - splitState_.commit = position; - - encodeBuffer.encodeValue(diffCommit, 32, 5); - - // - // Send the resource id and the commit - // flag. - // - - encodeBuffer.encodeCachedValue(resource, 8, - clientCache_ -> resourceCache); - - encodeBuffer.encodeBoolValue(commit); - - // - // Remove the split from the split queue. - // - - Split *split = handleSplitCommitRemove(request, resource, splitState_.commit); - - if (split == NULL) - { - return -1; - } - - clientStore_ -> getCommitStore() -> update(split); - - // - // Free the split. - // - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleCommitSplitRequest: SPLIT! Freeing up the " - << "committed split.\n" << logofs_flush; - #endif - - delete split; - - return 1; -} - -int ClientChannel::handleAbortSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - unsigned char resource = *(buffer + 1); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleAbortSplitRequest: SPLIT! Handling abort split " - << "request for FD#"<< fd_ << " and resource " - << (unsigned int) resource << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(resource, 8, - clientCache_ -> resourceCache); - - SplitStore *splitStore = clientStore_ -> getSplitStore(resource); - - if (splitStore == NULL) - { - #ifdef WARNING - *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The split " - << "store [" << (unsigned int) resource << "] " - << "is already empty.\n" << logofs_flush; - #endif - - return 0; - } - - // - // Loop through the messages in the split - // store and discard from the memory cache - // the messages that are still incomplete. - // Then remove the message from the split - // store. - // - - #if defined(TEST) || defined(SPLIT) - - clientStore_ -> dumpSplitStore(resource); - - #endif - - int splits = 0; - - Split *splitMessage; - - for (;;) - { - splitMessage = splitStore -> getFirstSplit(); - - if (splitMessage == NULL) - { - // - // Check if we had created the store - // but no message was added yet. - // - - #ifdef WARNING - - if (splits == 0) - { - *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The " - << "split store [" << (unsigned int) resource - << "] is unexpectedly empty.\n" - << logofs_flush; - } - - #endif - - break; - } - - // - // Splits already aborted can't be in the - // split store. - // - - #if defined(TEST) || defined(SPLIT) - - if (splitMessage -> getState() == split_aborted) - { - *logofs << "handleAbortSplitRequest: PANIC! SPLIT! Found an " - << "aborted split in store [" << (unsigned int) resource - << "].\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - if (splitMessage -> getAction() == IS_HIT) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleAbortSplitRequest: SPLIT! Removing the " - << "split from the memory cache.\n" - << logofs_flush; - #endif - - splitMessage -> getStore() -> remove(splitMessage -> getPosition(), - use_checksum, discard_data); - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleAbortSplitRequest: SPLIT! Removing the " - << "split from the split store.\n" - << logofs_flush; - #endif - - splitMessage = splitStore -> pop(); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleAbortSplitRequest: SPLIT! Freeing up the " - << "aborted split.\n" << logofs_flush; - #endif - - delete splitMessage; - - splits++; - } - - // - // If the start-split/end-split sequence - // was closed, send the notification now, - // else wait for the end-split. - // - - if (resource != splitState_.resource) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleAbortSplitRequest: SPLIT! Sending the " - << "deferred [end split] event.\n" - << logofs_flush; - #endif - - handleRestart(sequence_deferred, resource); - } - #if defined(TEST) || defined(SPLIT) - else - { - *logofs << "handleAbortSplitRequest: WARNING! SPLIT! Still " - << "waiting for the closure of the split " - << "sequence.\n" << logofs_flush; - } - #endif - - // - // Check if there is any other store - // having splits to send. - // - - handleSplitPending(); - - return (splits > 0); -} - -int ClientChannel::handleFinishSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - unsigned char resource = *(buffer + 1); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleFinishSplitRequest: SPLIT! Handling finish split " - << "request for FD#"<< fd_ << " and resource " - << (unsigned int) resource << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(resource, 8, - clientCache_ -> resourceCache); - - // - // We need to get the protocol statistics - // for the finish message we are handling - // here because sending a new split will - // reset the bits counter. - // - - int bits = encodeBuffer.diffBits(); - - statistics -> addRequestBits(opcode, size << 3, bits); - - SplitStore *splitStore = clientStore_ -> getSplitStore(resource); - - if (splitStore == NULL) - { - #ifdef WARNING - *logofs << "handleFinishSplitRequest: WARNING! SPLIT! The split " - << "store [" << (unsigned int) resource << "] " - << "is already empty.\n" << logofs_flush; - #endif - - return 0; - } - - // - // Send all the split queued for the given - // resource until the split store becomes - // empty. - // - - #if defined(TEST) || defined(SPLIT) - - clientStore_ -> dumpSplitStore(resource); - - #endif - - Split *splitMessage; - - int total = MESSAGE_DATA_LIMIT; - - int bytes = total; - int splits = 0; - - for (;;) - { - splitMessage = splitStore -> getFirstSplit(); - - if (splitMessage == NULL) - { - // - // We have presumably created the store - // after a start split but no message - // was added yet. - // - - #ifdef WARNING - *logofs << "handleFinishSplitRequest: WARNING! SPLIT! The " - << "split store [" << (unsigned int) resource - << "] is unexpectedly empty.\n" - << logofs_flush; - #endif - - break; - } - - // - // Splits already aborted can't be in the - // split store. - // - - #if defined(TEST) || defined(SPLIT) - - if (splitMessage -> getState() == split_aborted) - { - *logofs << "handleFinishSplitRequest: PANIC! SPLIT! Found an " - << "aborted split in store [" << (unsigned int) resource - << "].\n" << logofs_flush; - - HandleCleanup(); - } - - *logofs << "handleFinishSplitRequest: SPLIT! Sending more " - << "data for store [" << (unsigned int) resource - << "].\n" << logofs_flush; - #endif - - if (handleSplitSend(encodeBuffer, resource, splits, bytes) < 0) - { - return -1; - } - - // - // Check if the split store was deleted. - // - - if (clientStore_ -> getSplitStore(resource) == NULL) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleFinishSplitRequest: SPLIT! Exiting " - << "from the finish loop with split store [" - << (unsigned int) resource << "] destroyed.\n" - << logofs_flush; - #endif - - break; - } - } - - // - // Check if there is any other store - // having splits to send. - // - - handleSplitPending(); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleFinishSplitRequest: SPLIT! Sent " << splits - << " splits and " << total - bytes << " bytes for FD#" << fd_ - << " with " << clientStore_ -> getSplitTotalStorageSize() - << " bytes and [" << clientStore_ -> getSplitTotalSize() - << "] splits remaining.\n" << logofs_flush; - #endif - - return (splits > 0); -} - -int ClientChannel::handleConfiguration() -{ - #ifdef TEST - *logofs << "ClientChannel: Setting new buffer parameters.\n" - << logofs_flush; - #endif - - readBuffer_.setSize(control -> ClientInitialReadSize, - control -> ClientMaximumBufferSize); - - writeBuffer_.setSize(control -> TransportXBufferSize, - control -> TransportXBufferThreshold, - control -> TransportMaximumBufferSize); - - transport_ -> setSize(control -> TransportXBufferSize, - control -> TransportXBufferThreshold, - control -> TransportMaximumBufferSize); - - return 1; -} - -int ClientChannel::handleFinish() -{ - #ifdef TEST - *logofs << "ClientChannel: Finishing channel for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - congestion_ = 0; - priority_ = 0; - - finish_ = 1; - - taintCounter_ = 0; - - splitState_.resource = nothing; - splitState_.pending = 0; - splitState_.commit = 0; - splitState_.mode = split_none; - - transport_ -> finish(); - - return 1; -} - -// -// If differential compression is disabled then use the -// most simple encoding but handle the image requests -// and the X_ListExtensions and X_QueryExtension messa- -// ges (needed to detect the opcode of the shape or the -// other extensions) in the usual way. -// - -int ClientChannel::handleFastReadRequest(EncodeBuffer &encodeBuffer, const unsigned char &opcode, - const unsigned char *&buffer, const unsigned int &size) -{ - // - // All the NX requests are handled in the - // main message loop. The X_PutImage can - // be handled here only if the split was - // not requested (since ProtoStep7 #issue 108). - // - - if ((opcode >= X_NXFirstOpcode && opcode <= X_NXLastOpcode) || - (opcode == X_PutImage && splitState_.resource != nothing) || - opcode == X_ListExtensions || - opcode == X_QueryExtension) - { - return 0; - } - - #ifdef DEBUG - *logofs << "handleFastReadRequest: Encoding raw request OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ - << " with size " << size << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeMemory(buffer, size); - - // - // Put request on the fast track - // if it needs a reply. - // - - switch (opcode) - { - case X_GetAtomName: - case X_GetGeometry: - case X_GetInputFocus: - case X_GetModifierMapping: - case X_GetKeyboardMapping: - case X_GetProperty: - case X_GetSelectionOwner: - case X_GrabPointer: - case X_GrabKeyboard: - case X_ListExtensions: - case X_ListFonts: - case X_LookupColor: - case X_AllocNamedColor: - case X_QueryPointer: - case X_GetWindowAttributes: - case X_QueryTree: - case X_QueryBestSize: - case X_QueryColors: - case X_QueryFont: - case X_TranslateCoords: - case X_GetImage: - case X_GetPointerMapping: - case X_GetKeyboardControl: - case X_InternAtom: - case X_AllocColor: - { - sequenceQueue_.push(clientSequence_, opcode); - - priority_++; - - break; - } - default: - { - break; - } - } - - int bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) - - *logofs << "handleFastReadRequest: Handled raw request OPCODE#" - << (unsigned int) opcode << " (" << DumpOpcode(opcode) << ")" - << " for FD#" << fd_ << " sequence " << clientSequence_ - << ". " << size << " bytes in, " << bits << " bits (" - << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; - - #endif - - statistics -> addRequestBits(opcode, size << 3, bits); - - if (opcode == opcodeStore_ -> renderExtension) - { - statistics -> addRenderRequestBits(*(buffer + 1), size << 3, bits); - } - - return 1; -} - -int ClientChannel::handleFastWriteReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - if ((opcode >= X_NXFirstOpcode && - opcode <= X_NXLastOpcode) || - opcode == X_ListExtensions || - opcode == X_QueryExtension) - { - return 0; - } - - #ifdef DEBUG - *logofs << "handleFastWriteReply: Decoding raw reply OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - buffer = writeBuffer_.addMessage(8); - - #ifndef __sun - - unsigned int *next = (unsigned int *) decodeBuffer.decodeMemory(8); - - *((unsigned int *) buffer) = *next++; - *((unsigned int *) (buffer + 4)) = *next; - - #else /* #ifndef __sun */ - - memcpy(buffer, decodeBuffer.decodeMemory(8), 8); - - #endif /* #ifndef __sun */ - - size = 32 + (GetULONG(buffer + 4, bigEndian_) << 2); - - writeBuffer_.registerPointer(&buffer); - - if (writeBuffer_.getAvailable() < size - 8 || - (int) size >= control -> TransportFlushBufferSize) - { - #ifdef DEBUG - *logofs << "handleFastWriteReply: Using scratch buffer for OPCODE#" - << (unsigned int) opcode << " with size " << size << " and " - << writeBuffer_.getLength() << " bytes in buffer.\n" - << logofs_flush; - #endif - - writeBuffer_.removeMessage(8); - - buffer = writeBuffer_.addScratchMessage(((unsigned char *) - decodeBuffer.decodeMemory(size - 8)) - 8, size); - } - else - { - writeBuffer_.addMessage(size - 8); - - #ifndef __sun - - if (size == 32) - { - next = (unsigned int *) decodeBuffer.decodeMemory(size - 8); - - for (int i = 8; i < 32; i += sizeof(unsigned int)) - { - *((unsigned int *) (buffer + i)) = *next++; - } - } - else - { - memcpy(buffer + 8, decodeBuffer.decodeMemory(size - 8), size - 8); - } - - #else /* #ifndef __sun */ - - memcpy(buffer + 8, decodeBuffer.decodeMemory(size - 8), size - 8); - - #endif /* #ifndef __sun */ - } - - writeBuffer_.unregisterPointer(); - - // - // We don't need to write our local sequence - // number. Replies are always sent with the - // original X server's sequence number. - // - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleFastWriteReply: Handled raw reply OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ << " with sequence " - << serverSequence_ << ". Output size is " << size << ".\n" - << logofs_flush; - #endif - - #ifdef DEBUG - *logofs << "handleFastWriteReply: Length of sequence queue is " - << sequenceQueue_.length() << ".\n" << logofs_flush; - #endif - - statistics -> addRepliedRequest(opcode); - - handleFlush(flush_if_needed); - - return 1; -} - -int ClientChannel::handleFastWriteEvent(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - #ifdef DEBUG - *logofs << "handleFastWriteEvent: Decoding raw " - << (opcode == X_Error ? "error" : "event") << " OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - size = 32; - - buffer = writeBuffer_.addMessage(size); - - #ifndef __sun - - unsigned int *next = (unsigned int *) decodeBuffer.decodeMemory(size); - - for (int i = 0; i < 32; i += sizeof(unsigned int)) - { - *((unsigned int *) (buffer + i)) = *next++; - } - - #else /* #ifndef __sun */ - - memcpy(buffer, decodeBuffer.decodeMemory(size), size); - - #endif /* #ifndef __sun */ - - // - // Use our local sequence number. - // - - PutUINT(lastSequence_, buffer + 2, bigEndian_); - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleFastWriteEvent: Handled raw " - << (opcode == X_Error ? "error" : "event") << " OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ << " with sequence " - << lastSequence_ << ". Output size is " << size << ".\n" - << logofs_flush; - #endif - - // - // Check if we need to suppress the error. - // - - if (opcode == X_Error && handleTaintSyncError(*(buffer + 10)) > 0) - { - #if defined(TEST) || defined(OPCODES) - *logofs << "handleFastWriteEvent: WARNING! Suppressed error OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ - << " with sequence " << lastSequence_ << ".\n" - << logofs_flush; - #endif - - writeBuffer_.removeMessage(32); - } - - handleFlush(flush_if_needed); - - return 1; -} - -int ClientChannel::handleShmemRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - // - // Will push sequence and set - // priority according to stage. - // - - unsigned int stage = *(buffer + 1); - - #ifdef TEST - *logofs << "handleShmemRequest: Encoding shmem request " - << "OPCODE#" << (unsigned int) opcode << " for FD#" - << fd_ << " with size " << size << " at stage " - << stage << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeValue(stage, 2); - - if (stage == 0) - { - unsigned int enableClient = 0; - unsigned int enableServer = 0; - - if (control -> ShmemClient == 1) - { - enableClient = *(buffer + 4); - } - - if (control -> ShmemServer == 1) - { - enableServer = *(buffer + 5); - } - - encodeBuffer.encodeBoolValue(enableClient); - encodeBuffer.encodeBoolValue(enableServer); - - unsigned int clientSegment = GetULONG(buffer + 8, bigEndian_); - unsigned int serverSegment = GetULONG(buffer + 12, bigEndian_); - - encodeBuffer.encodeValue(clientSegment, 29, 9); - encodeBuffer.encodeValue(serverSegment, 29, 9); - - #ifdef TEST - *logofs << "handleShmemRequest: Enable client is " - << enableClient << " enable server is " << enableServer - << " client segment is " << (void *) clientSegment - << " server segment is " << (void *) serverSegment - << ".\n" << logofs_flush; - #endif - - #ifdef TEST - *logofs << "handleShmemRequest: Size of the shared memory " - << "segment will be " << control -> ShmemServerSize - << ".\n" << logofs_flush; - #endif - } - - if (stage != 1) - { - sequenceQueue_.push(clientSequence_, opcodeStore_ -> - getShmemParameters); - - priority_++; - } - - return 1; -} - -int ClientChannel::handleShmemReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - #ifdef TEST - *logofs << "handleShmemReply: Received shmem parameters " - << "reply OPCODE#" << (unsigned int) opcode - << ".\n" << logofs_flush; - #endif - - size = 32; - buffer = writeBuffer_.addMessage(size); - - unsigned int stage; - - decodeBuffer.decodeValue(stage, 2); - - *(buffer + 1) = stage; - - if (stage == 2) - { - unsigned int clientEnabled; - unsigned int serverEnabled; - - decodeBuffer.decodeBoolValue(clientEnabled); - decodeBuffer.decodeBoolValue(serverEnabled); - - // - // Client support is not implemented - // and not useful. It is here only - // for compatibility. - // - - clientEnabled = 0; - - *(buffer + 8) = clientEnabled; - *(buffer + 9) = serverEnabled; - - PutULONG(0, buffer + 12, bigEndian_); - - if (serverEnabled == 1) - { - #ifdef TEST - *logofs << "handleShmemReply: Enabled shared memory " - << "support in X server with segment size " - << control -> ShmemServerSize << ".\n" - << logofs_flush; - #endif - - PutULONG(control -> ShmemServerSize, buffer + 16, bigEndian_); - } - else - { - PutULONG(0, buffer + 16, bigEndian_); - } - } - else - { - *(buffer + 8) = 0; - *(buffer + 9) = 0; - - PutULONG(0, buffer + 12, bigEndian_); - PutULONG(0, buffer + 16, bigEndian_); - } - - return 1; -} - -int ClientChannel::handleFontRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - #ifdef TEST - *logofs << "handleFontRequest: Encoding font request " - << "OPCODE#" << (unsigned int) opcode << " for FD#" - << fd_ << " with size " << size << ".\n" - << logofs_flush; - #endif - - sequenceQueue_.push(clientSequence_, opcodeStore_ -> - getFontParameters); - - return 1; -} - -int ClientChannel::handleFontReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - #ifdef TEST - *logofs << "handleFontReply: Received font operation " - << "reply OPCODE#" << (unsigned int) opcode - << ".\n" << logofs_flush; - #endif - - unsigned int length; - - decodeBuffer.decodeValue(length, 8); - - size = 32 + RoundUp4(length + 1); - buffer = writeBuffer_.addMessage(size); - - unsigned char *next = buffer + 32; - - *next++ = length; - - decodeBuffer.decodeTextData(next, length); - - #ifdef TEST - - *logofs << "handleFontReply: Received tunneled font server " - << "path '"; - - for (unsigned int i = 0; i < length; i++) - { - *logofs << *(buffer + 32 + 1 + i); - } - - *logofs << "' for FD#" << fd_ << ".\n" << logofs_flush; - - #endif - - if (fontPort_ == -1) - { - // - // The local side is not going to forward - // the font server connections. - // - - #ifdef TEST - *logofs << "handleFontReply: WARNING! Returning an empty " - << "font server path.\n" << logofs_flush; - #endif - - writeBuffer_.removeMessage(size); - - size = 36; - buffer = writeBuffer_.addMessage(size); - - // - // Set the length of the returned - // path to 0. - // - - *(buffer + 32) = 0; - } - #ifdef TEST - else - { - *logofs << "handleFontReply: Returning the received " - << "font server path.\n" << logofs_flush; - } - #endif - - return 1; -} - -int ClientChannel::handleCacheRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - #ifdef TEST - *logofs << "handleCacheRequest: Handling cache request " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - enableCache_ = *(buffer + 4); - enableSplit_ = *(buffer + 5); - enableSave_ = *(buffer + 6); - enableLoad_ = *(buffer + 7); - - #ifdef TEST - *logofs << "handleCacheRequest: Set cache parameters to " - << " cache " << enableCache_ << " split " << enableSplit_ - << " save " << enableSave_ << " load " << enableLoad_ - << ".\n" << logofs_flush; - #endif - - // - // Encode all the parameters as a - // single unsigned int so we can - // use an int cache. - // - - unsigned int mask = enableSave_ << 8 | enableLoad_; - - encodeBuffer.encodeCachedValue(mask, 32, clientCache_ -> - setCacheParametersCache); - return 0; -} - -int ClientChannel::handleStartSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - #if defined(TEST) || defined(SPLIT) - *logofs << "handleStartSplitRequest: SPLIT! Handling start split " - << "request for FD#"<< fd_ << ".\n" << logofs_flush; - #endif - - if (splitState_.resource != nothing) - { - #ifdef PANIC - *logofs << "handleStartSplitRequest: PANIC! SPLIT! Split requested " - << "for resource id " << (unsigned int) *(buffer + 1) - << " while handling resource " << splitState_.resource - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Split requested for " - << "resource id " << (unsigned int) *(buffer + 1) - << " while handling resource " << splitState_.resource - << ".\n"; - - return -1; - } - else if (fd_ != firstClient_) - { - // - // It can be that an auxiliary channel is the - // first to connect, then comes the agent that - // is actually using the NX opcodes. - // - - #ifdef WARNING - *logofs << "handleStartSplitRequest: WARNING SPLIT! Split requested " - << "on FD#" << fd_ << " while expecting FD#" << firstClient_ - << ".\n" << logofs_flush; - #endif - - firstClient_ = fd_; - } - - // - // Set the agent's resource for which we are - // going to split the request. - // - - splitState_.resource = *(buffer + 1); - - #if defined(TEST) || defined(SPLIT) - - *logofs << "handleStartSplitRequest: SPLIT! Registered id " - << splitState_.resource << " as resource " - << "waiting for a split.\n" << logofs_flush; - - if (clientStore_ -> getSplitStore(splitState_.resource) != NULL) - { - *logofs << "handleStartSplitRequest: WARNING! SPLIT! A split " - << "store for resource id " << splitState_.resource - << " already exists.\n" << logofs_flush; - - clientStore_ -> dumpSplitStore(splitState_.resource); - } - - #endif - - // - // Send the selected resource to the remote. - // - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeCachedValue(splitState_.resource, 8, - clientCache_ -> resourceCache); - - splitState_.mode = (T_split_mode) *(buffer + 4); - - if (splitState_.mode != NXSplitModeAsync && - splitState_.mode != NXSplitModeSync) - { - splitState_.mode = (T_split_mode) control -> SplitMode; - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleStartSplitRequest: SPLIT! Set split " - << "mode to '" << splitState_.mode << "' with " - << "provided value '" << (unsigned) *(buffer + 4) - << "'.\n" << logofs_flush; - #endif - } - - #if defined(TEST) || defined(SPLIT) - - if (splitState_.mode == NXSplitModeAsync) - { - *logofs << "handleStartSplitRequest: SPLIT! Selected split " - << "mode is [split_async].\n" << logofs_flush; - } - else if (splitState_.mode == NXSplitModeSync) - { - *logofs << "handleStartSplitRequest: SPLIT! Selected split " - << "mode is [split_sync].\n" << logofs_flush; - } - - clientStore_ -> dumpSplitStores(); - - #endif - - return 1; -} - -int ClientChannel::handleEndSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - #if defined(TEST) || defined(SPLIT) - *logofs << "handleEndSplitRequest: SPLIT! Handling end split " - << "request for FD#"<< fd_ << ".\n" << logofs_flush; - #endif - - // - // Verify that the agent resource matches. - // - - if (splitState_.resource == nothing) - { - #ifdef PANIC - *logofs << "handleEndSplitRequest: PANIC! SPLIT! Received an end of " - << "split for resource id " << (unsigned int) *(buffer + 1) - << " without a previous start.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Received an end of split " - << "for resource id " << (unsigned int) *(buffer + 1) - << " without a previous start.\n"; - - return -1; - } - else if (splitState_.resource != *(buffer + 1)) - { - #ifdef PANIC - *logofs << "handleEndSplitRequest: PANIC! SPLIT! Invalid resource id " - << (unsigned int) *(buffer + 1) << " received while " - << "waiting for resource id " << splitState_.resource - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid resource id " - << (unsigned int) *(buffer + 1) << " received while " - << "waiting for resource id " << splitState_.resource - << ".\n"; - - return -1; - } - - // - // Send the selected resource to the remote. - // - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeCachedValue(splitState_.resource, 8, - clientCache_ -> resourceCache); - - // - // Send the split notification events - // to the agent. - // - - handleRestart(sequence_immediate, splitState_.resource); - - // - // Check if we still have splits to send. - // - - handleSplitPending(); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleEndSplitRequest: SPLIT! Reset id " - << splitState_.resource << " as resource " - << "selected for splits.\n" << logofs_flush; - #endif - - splitState_.resource = nothing; - splitState_.mode = split_none; - - #if defined(TEST) || defined(SPLIT) - - clientStore_ -> dumpSplitStores(); - - #endif - - return 1; -} - -void ClientChannel::handleDecodeCharInfo(DecodeBuffer &decodeBuffer, unsigned char *nextDest) -{ - unsigned int value; - - decodeBuffer.decodeCachedValue(value, 32, - *serverCache_ -> queryFontCharInfoCache[0], 6); - - PutUINT(value & 0xffff, nextDest, bigEndian_); - PutUINT(value >> 16, nextDest + 10, bigEndian_); - - nextDest += 2; - - for (unsigned int i = 1; i < 5; i++) - { - unsigned int value; - - decodeBuffer.decodeCachedValue(value, 16, - *serverCache_ -> queryFontCharInfoCache[i], 6); - - PutUINT(value, nextDest, bigEndian_); - - nextDest += 2; - } -} - -int ClientChannel::setBigEndian(int flag) -{ - bigEndian_ = flag; - - return 1; -} - -int ClientChannel::setReferences() -{ - #ifdef TEST - *logofs << "ClientChannel: Initializing the static " - << "members for the client channels.\n" - << logofs_flush; - #endif - - #ifdef REFERENCES - - references_ = 0; - - #endif - - return 1; -} diff --git a/nxcomp/ClientChannel.h b/nxcomp/ClientChannel.h deleted file mode 100644 index ae92648d5..000000000 --- a/nxcomp/ClientChannel.h +++ /dev/null @@ -1,434 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ClientChannel_H -#define ClientChannel_H - -#include "List.h" -#include "Channel.h" - -#include "SequenceQueue.h" - -#include "ClientReadBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// If defined, the client channel will -// have the chance of suppressing more -// opcodes for test purposes. -// - -#undef LAME - -// -// Define this to log a line when a -// channel is created or destroyed. -// - -#undef REFERENCES - -// -// This class implements the X client -// side compression of the protocol. -// - -class ClientChannel : public Channel -{ - public: - - ClientChannel(Transport *transport, StaticCompressor *compressor); - - virtual ~ClientChannel(); - - virtual int handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, - unsigned int length); - - virtual int handleWrite(const unsigned char *message, unsigned int length); - - virtual int handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, - T_store_action action, int position, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - virtual int handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, - T_store_action action, int position, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) - { - return 0; - } - - virtual int handleSplit(EncodeBuffer &encodeBuffer); - - virtual int handleSplit(DecodeBuffer &decodeBuffer) - { - return 0; - } - - virtual int handleSplitEvent(EncodeBuffer &encodeBuffer, Split *split); - - virtual int handleSplitEvent(DecodeBuffer &decodeBuffer); - - virtual int handleMotion(EncodeBuffer &encodeBuffer) - { - return 0; - } - - virtual int handleCompletion(EncodeBuffer &encodeBuffer) - { - return 0; - } - - virtual int handleConfiguration(); - - virtual int handleFinish(); - - virtual int handleAsyncEvents() - { - return 0; - } - - virtual int needSplit() const - { - #if defined(TEST) || defined(SPLIT) - *logofs << "needSplit: SPLIT! Returning pending split " - << "flag " << splitState_.pending << " with " - << clientStore_ -> getSplitTotalSize() - << " splits in the split stores.\n" - << logofs_flush; - #endif - - return splitState_.pending; - } - - virtual int needMotion() const - { - return 0; - } - - virtual T_channel_type getType() const - { - return channel_x11; - } - - int setBigEndian(int flag); - - // - // Initialize the static members. - // - - static int setReferences(); - - private: - - int handleFastReadRequest(EncodeBuffer &encodeBuffer, const unsigned char &opcode, - const unsigned char *&buffer, const unsigned int &size); - - int handleFastWriteReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - int handleFastWriteEvent(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - // - // Intercept the request before the opcode - // is encoded. - // - - int handleTaintRequest(unsigned char &opcode, const unsigned char *&buffer, - unsigned int &size) - { - if (control -> TaintReplies > 0 && - opcode == X_GetInputFocus) - { - return handleTaintSyncRequest(opcode, buffer, size); - } - - #ifdef LAME - - return handleTaintLameRequest(opcode, buffer, size); - - #endif - - return 0; - } - - int handleTaintLameRequest(unsigned char &opcode, const unsigned char *&buffer, - unsigned int &size); - - int handleTaintSyncRequest(unsigned char &opcode, const unsigned char *&buffer, - unsigned int &size); - - int handleTaintSyncError(unsigned char opcode); - - // - // How to handle sequence counter - // in notification event. - // - - enum T_sequence_mode - { - sequence_immediate, - sequence_deferred - }; - - // - // Send split notifications to the - // agent. - // - - int handleRestart(T_sequence_mode mode, int resource); - - int handleNotify(T_notification_type type, T_sequence_mode mode, - int resource, int request, int position); - - // - // Other utility functions used in - // handling of the image streaming. - // - - int mustSplitMessage(int resource) - { - return (clientStore_ -> getSplitStore(resource) -> - getSize() != 0); - } - - int canSplitMessage(T_split_mode mode, unsigned int size) - { - return ((int) size >= control -> SplitDataThreshold && - (clientStore_ -> getSplitTotalStorageSize() < control -> - SplitTotalStorageSize && clientStore_ -> - getSplitTotalSize() < control -> SplitTotalSize)); - } - - int canSendSplit(Split *split) - { - return (split -> getMode() != split_sync || - split -> getState() == split_missed || - split -> getState() == split_loaded); - } - - int handleSplitSend(EncodeBuffer &encodeBuffer, int resource, - int &total, int &bytes); - - Split *handleSplitFind(T_checksum checksum, int resource); - - int handleSplitChecksum(EncodeBuffer &encodeBuffer, T_checksum checksum); - - void handleSplitPending(int resource) - { - if (splitState_.pending == 0) - { - if (clientStore_ -> getSplitStore(resource) != NULL && - clientStore_ -> getSplitStore(resource) -> - getFirstSplit() != NULL) - { - splitState_.pending = canSendSplit(clientStore_ -> - getSplitStore(resource) -> getFirstSplit()); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitPending: SPLIT! Set the pending " - << "split flag to " << splitState_.pending - << " with " << clientStore_ -> getSplitTotalSize() - << " splits in the split stores.\n" - << logofs_flush; - #endif - } - } - } - - // - // Scan all the split stores to find - // if there is any split to send. - // - - void handleSplitPending(); - - // - // Handle the MIT-SHM initialization - // messages exchanged with the remote - // proxy. - // - - int handleShmemRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - int handleShmemReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - // - // Query the port used to tunnel - // the font server connections. - // - - int handleFontRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - int handleFontReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - // - // Let the agent set the cache - // policy for image requests. - // - - int handleCacheRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - // - // Encode the start and end split - // requests. - // - - int handleStartSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - int handleEndSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - // - // Empty a split store and send the - // restart event. - // - - int handleAbortSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - // - // Force the proxy to finalize all - // the pending split operations and - // restart a resource. - // - - int handleFinishSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - // - // Tell the remote peer to send the - // split requests to the X server. - // - - int handleCommitSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - // - // Other utilities. - // - - void handleDecodeCharInfo(DecodeBuffer &, unsigned char *); - - // - // Own read buffer. It is able to identify - // full messages read from the X descriptor. - // - - ClientReadBuffer readBuffer_; - - // - // Sequence number of last request coming - // from the X client or the X server. - // - - unsigned int clientSequence_; - unsigned int serverSequence_; - - // - // Last sequence number known by client. It can - // be the real sequence generated by server or - // the one of the last auto-generated event. - // - - unsigned int lastSequence_; - - // - // Used to identify replies based on sequence - // number of original request. - // - - SequenceQueue sequenceQueue_; - - // - // This is used to test the synchronous flush - // in the proxy. - // - - int lastRequest_; - - // - // Current resource id selected as target and - // other information related to the image split. - // The pending and abort flags are set when we - // want the proxy to give us a chance to send - // more split data. We also save the position - // of the last commit operation performed by - // channel so we can differentially encode the - // position of next message to commit. - // - - typedef struct - { - int resource; - int pending; - int commit; - T_split_mode mode; - - } T_split_state; - - T_split_state splitState_; - - // - // List of agent resources. - // - - List splitResources_; - - // - // How many sync requests we - // have tainted so far. - // - - int taintCounter_; - - private: - - // - // Keep track of object - // creation and deletion. - // - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -#endif /* ClientChannel_H */ diff --git a/nxcomp/ClientProxy.cpp b/nxcomp/ClientProxy.cpp deleted file mode 100644 index 3df45331a..000000000 --- a/nxcomp/ClientProxy.cpp +++ /dev/null @@ -1,549 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Socket.h" -#include "Agent.h" - -#include "ClientProxy.h" - -#include "ClientChannel.h" -#include "GenericChannel.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Log the operations related to sending -// and receiving the control tokens. -// - -#undef TOKEN - -ClientProxy::ClientProxy(int proxyFd) : Proxy(proxyFd) -{ - fontServerPort_ = NULL; - - #ifdef DEBUG - *logofs << "ClientProxy: Created new object at " << this - << ".\n" << logofs_flush; - #endif -} - -ClientProxy::~ClientProxy() -{ - delete [] fontServerPort_; - - #ifdef DEBUG - *logofs << "ClientProxy: Deleted object at " << this - << ".\n" << logofs_flush; - #endif -} - -void ClientProxy::handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, - sockaddr * xServerAddr, unsigned int xServerAddrLength) -{ - #ifdef DEBUG - *logofs << "ClientProxy: No display configuration to set.\n" - << logofs_flush; - #endif -} - -void ClientProxy::handlePortConfiguration(ChannelEndPoint &cupsServerPort, - ChannelEndPoint &smbServerPort, - ChannelEndPoint &mediaServerPort, - ChannelEndPoint &httpServerPort, - const char *fontServerPort) -{ - delete [] fontServerPort_; - - fontServerPort_ = new char[strlen(fontServerPort) + 1]; - - strcpy(fontServerPort_, fontServerPort); - - #ifdef DEBUG - *logofs << "ClientProxy: Set port configuration to font '" - << fontServerPort_ << "'.\n" - << logofs_flush; - #endif -} - -int ClientProxy::handleNewConnection(T_channel_type type, int clientFd) -{ - switch (type) - { - case channel_x11: - { - return handleNewXConnection(clientFd); - } - case channel_cups: - { - return handleNewGenericConnection(clientFd, channel_cups, "CUPS"); - } - case channel_smb: - { - return handleNewGenericConnection(clientFd, channel_smb, "SMB"); - } - case channel_media: - { - return handleNewGenericConnection(clientFd, channel_media, "media"); - } - case channel_http: - { - return handleNewGenericConnection(clientFd, channel_http, "HTTP"); - } - case channel_slave: - { - return handleNewSlaveConnection(clientFd); - } - default: - { - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Unsupported channel with type '" - << getTypeName(type) << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unsupported channel with type '" - << getTypeName(type) << "'.\n"; - - return -1; - } - } -} - -int ClientProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId) -{ - switch (type) - { - case channel_font: - { - int port = atoi(fontServerPort_); - - if (port > 0) - { - // - // Connect on the TCP port number. - // - - return handleNewGenericConnectionFromProxyTCP(channelId, channel_font, "localhost", - port, "font"); - } - else - { - // - // Connect to the Unix path. - // - - return handleNewGenericConnectionFromProxyUnix(channelId, channel_font, - fontServerPort_, "font"); - } - } - case channel_slave: - { - return handleNewSlaveConnectionFromProxy(channelId); - } - default: - { - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Unsupported channel with type '" - << getTypeName(type) << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unsupported channel with type '" - << getTypeName(type) << "'.\n"; - - return -1; - } - } -} - -int ClientProxy::handleNewAgentConnection(Agent *agent) -{ - int clientFd = agent -> getLocalFd(); - - int channelId = allocateChannelMap(clientFd); - - if (channelId == -1) - { - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Maximum number of available " - << "channels exceeded.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Maximum number of available " - << "channels exceeded.\n"; - - return -1; - } - - transports_[channelId] = agent -> getTransport(); - - agent_ = channelId; - - return handleNewXConnection(clientFd); -} - -int ClientProxy::handleNewXConnection(int clientFd) -{ - int channelId = getChannel(clientFd); - - // - // Check if the channel has been - // already mapped. - // - - if (channelId == -1) - { - channelId = allocateChannelMap(clientFd); - - if (channelId == -1) - { - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Maximum number of available " - << "channels exceeded.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Maximum number of available " - << "channels exceeded.\n"; - - return -1; - } - } - - #ifdef TEST - *logofs << "ClientProxy: X client descriptor FD#" << clientFd - << " mapped to channel ID#" << channelId << ".\n" - << logofs_flush; - #endif - - // - // Turn queuing off for path proxy-to-X-client. - // - - if (control -> OptionClientNoDelay == 1) - { - SetNoDelay(clientFd, control -> OptionClientNoDelay); - } - - // - // If requested, set the size of the TCP send - // and receive buffers. - // - - if (control -> OptionClientSendBuffer != -1) - { - SetSendBuffer(clientFd, control -> OptionClientSendBuffer); - } - - if (control -> OptionClientReceiveBuffer != -1) - { - SetReceiveBuffer(clientFd, control -> OptionClientReceiveBuffer); - } - - if (allocateTransport(clientFd, channelId) < 0) - { - return -1; - } - - // - // Starting from protocol level 3 client and server - // caches are created in proxy and shared between all - // channels. If remote proxy has older protocol level - // pointers are NULL and channels must create their - // own instances. - // - - channels_[channelId] = new ClientChannel(transports_[channelId], compressor_); - - if (channels_[channelId] == NULL) - { - deallocateTransport(channelId); - - return -1; - } - - increaseChannels(channelId); - - // - // Propagate channel stores and caches to the new - // channel. - // - - channels_[channelId] -> setOpcodes(opcodeStore_); - - channels_[channelId] -> setStores(clientStore_, serverStore_); - - channels_[channelId] -> setCaches(clientCache_, serverCache_); - - int port = atoi(fontServerPort_); - - if (port > 0 || *fontServerPort_ != '\0') - { - channels_[channelId] -> setPorts(1); - } - - if (handleControl(code_new_x_connection, channelId) < 0) - { - return -1; - } - - // - // Let channel configure itself according - // to control parameters. - // - - channels_[channelId] -> handleConfiguration(); - - return 1; -} - -int ClientProxy::handleNewXConnectionFromProxy(int channelId) -{ - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Can't create a new X channel " - << "with ID#" << channelId << " at this side.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create a new X channel " - << "with ID#" << channelId << " at this side.\n"; - - return -1; -} - -int ClientProxy::handleLoad(T_load_type type) -{ - int channelCount = getChannels(channel_x11); - - if ((channelCount == 0 && type == load_if_first) || - (channelCount > 0 && type == load_if_any)) - { - #ifdef TEST - *logofs << "ClientProxy: Going to load content of client store.\n" - << logofs_flush; - #endif - - int result = handleLoadStores(); - - if (result == 1) - { - if (handleControl(code_load_request) < 0) - { - return -1; - } - - priority_ = 1; - } - else if (result < 0) - { - #ifdef WARNING - *logofs << "ClientProxy: WARNING! Failed to load content " - << "of persistent cache.\n" << logofs_flush; - #endif - - // - // Don't abort the proxy connection in the case - // of a corrupted cache. By not sending the load - // message to the remote peer, both sides will - // start encoding messages using empty stores. - // This behaviour is compatible with old proxy - // versions. - // - - if (channelCount == 0 && type == load_if_first) - { - if (handleResetStores() < 0) - { - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Failed to reset message stores.\n" - << logofs_flush; - #endif - - return -1; - } - } - else - { - return -1; - } - } - } - else - { - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Can't load the stores with " - << channelCount << " remaining channels.\n" - << logofs_flush; - #endif - - return -1; - } - - return 1; -} - -int ClientProxy::handleSave() -{ - // - // If no more X channels are remaining - // then save content of message stores. - // - - int channelCount = getChannels(channel_x11); - - if (channelCount == 0) - { - int result = handleSaveStores(); - - if (result == 1) - { - if (handleControl(code_save_request) < 0) - { - return -1; - } - - priority_ = 1; - - return 1; - } - else if (result < 0) - { - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Failed to save stores " - << "to persistent cache.\n" << logofs_flush; - #endif - - return -1; - } - } - else - { - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Can't save the stores with " - << channelCount << " remaining channels.\n" - << logofs_flush; - #endif - - return -1; - } - - return 1; -} - -int ClientProxy::handleAsyncEvents() -{ - if (canRead() == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: WARNING! Reading while writing " - << "with data available on the proxy link.\n" - << logofs_flush; - #endif - - if (handleRead() < 0) - { - return -1; - } - - return 1; - } - - return 0; -} - -int ClientProxy::handleLoadFromProxy() -{ - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Invalid load control message " - << "received in proxy.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid load control message " - << "received in proxy.\n"; - - return -1; -} - -int ClientProxy::handleSaveFromProxy() -{ - #ifdef PANIC - *logofs << "ClientProxy: PANIC! Invalid save control message " - << "received in proxy.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid save control message " - << "received in proxy.\n"; - - return -1; -} - -int ClientProxy::handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient) const -{ - if (clientStore_ -> saveRequestStores(cachefs, md5StateStream, md5StateClient, - use_checksum, discard_data) < 0) - { - return -1; - } - else if (serverStore_ -> saveReplyStores(cachefs, md5StateStream, md5StateClient, - discard_checksum, use_data) < 0) - { - return -1; - } - else if (serverStore_ -> saveEventStores(cachefs, md5StateStream, md5StateClient, - discard_checksum, use_data) < 0) - { - return -1; - } - - return 1; -} - -int ClientProxy::handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const -{ - if (clientStore_ -> loadRequestStores(cachefs, md5StateStream, - use_checksum, discard_data) < 0) - { - return -1; - } - else if (serverStore_ -> loadReplyStores(cachefs, md5StateStream, - discard_checksum, use_data) < 0) - { - return -1; - } - else if (serverStore_ -> loadEventStores(cachefs, md5StateStream, - discard_checksum, use_data) < 0) - { - return -1; - } - - return 1; -} - diff --git a/nxcomp/ClientProxy.h b/nxcomp/ClientProxy.h deleted file mode 100644 index b89785b1a..000000000 --- a/nxcomp/ClientProxy.h +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ClientProxy_H -#define ClientProxy_H - -#include "Proxy.h" - -// -// Set the verbosity level. -// - -#undef TEST -#undef DEBUG - -class ClientProxy : public Proxy -{ - public: - - ClientProxy(int proxyFD); - - virtual ~ClientProxy(); - - virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, - sockaddr *xServerAddr, unsigned int xServerAddrLength); - - virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort, - ChannelEndPoint &smbServerPort, - ChannelEndPoint &mediaServerPort, - ChannelEndPoint &httpServerPort, - const char *fontServerPort); - - protected: - - // - // Create a new channel. - // - - virtual int handleNewConnection(T_channel_type type, int clientFd); - - virtual int handleNewConnectionFromProxy(T_channel_type type, int channelId); - - virtual int handleNewAgentConnection(Agent *agent); - - virtual int handleNewXConnection(int clientFd); - - virtual int handleNewXConnectionFromProxy(int channelId); - - // - // Implement persistence according - // to our proxy mode. - // - - virtual int handleLoad(T_load_type type); - virtual int handleSave(); - - virtual int handleAsyncEvents(); - - virtual int handleLoadFromProxy(); - virtual int handleSaveFromProxy(); - - virtual int handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient) const; - - virtual int handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const; - - // - // Utility function used to realize - // a new connection. - // - - protected: - - virtual int checkLocalChannelMap(int channelId) - { - // Since ProtoStep7 (#issue 108) - return ((channelId & control -> ChannelMask) != 0); - } - - // - // Ports where to forward extended services' - // TCP connections. - // - - private: - - char *fontServerPort_; -}; - - -#endif /* ClientProxy_H */ diff --git a/nxcomp/ClientReadBuffer.cpp b/nxcomp/ClientReadBuffer.cpp deleted file mode 100644 index 37502038f..000000000 --- a/nxcomp/ClientReadBuffer.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ClientReadBuffer.h" - -#include "ClientChannel.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -unsigned int ClientReadBuffer::suggestedLength(unsigned int pendingLength) -{ - // - // Even if the pending data is not - // enough to make a complete message, - // resize the buffer to accommodate - // it all. - // - - unsigned int readLength = pendingLength; - - if (pendingLength < remaining_) - { - readLength = remaining_; - } - - return readLength; -} - -int ClientReadBuffer::locateMessage(const unsigned char *start, - const unsigned char *end, - unsigned int &controlLength, - unsigned int &dataLength, - unsigned int &trailerLength) -{ - unsigned int size = end - start; - - #ifdef TEST - *logofs << "ClientReadBuffer: Locating message for FD#" - << transport_ -> fd() << " with " << size - << " bytes.\n" << logofs_flush; - #endif - - if (firstMessage_) - { - if (size < 12) - { - remaining_ = 12 - size; - - #ifdef TEST - *logofs << "ClientReadBuffer: No message was located " - << "with remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - - if (*start == 0x42) - { - bigEndian_ = 1; - } - else - { - bigEndian_ = 0; - } - - channel_ -> setBigEndian(bigEndian_); - - dataLength = 12 + RoundUp4(GetUINT(start + 6, bigEndian_)) + - RoundUp4(GetUINT(start + 8, bigEndian_)); - - // - // Send the data immediately if this is unlikely - // to be a X connection attempt. - // - - if (dataLength > 4096) - { - #ifdef WARNING - *logofs << "ClientReadBuffer: WARNING! Flushing suspicious X " - << "connection with first request of " << dataLength - << " bytes.\n" << logofs_flush; - #endif - - dataLength = size; - } - } - else - { - if (size < 4) - { - remaining_ = 4 - size; - - #ifdef TEST - *logofs << "ClientReadBuffer: No message was located " - << "with remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - - dataLength = (GetUINT(start + 2, bigEndian_) << 2); - - if (dataLength < 4) - { - #ifdef TEST - *logofs << "ClientReadBuffer: WARNING! Assuming length 4 " - << "for suspicious message of length " << dataLength - << ".\n" << logofs_flush; - #endif - - dataLength = 4; - } - } - - #ifdef TEST - *logofs << "ClientReadBuffer: Length of the next message is " - << dataLength << ".\n" << logofs_flush; - #endif - - if (size < dataLength) - { - remaining_ = dataLength - size; - - #ifdef TEST - *logofs << "ClientReadBuffer: No message was located " - << "with remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - - firstMessage_ = 0; - - controlLength = 0; - trailerLength = 0; - - remaining_ = 0; - - #ifdef TEST - *logofs << "ClientReadBuffer: Located message with " - << "remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 1; -} diff --git a/nxcomp/ClientReadBuffer.h b/nxcomp/ClientReadBuffer.h deleted file mode 100644 index c557417fa..000000000 --- a/nxcomp/ClientReadBuffer.h +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ClientReadBuffer_H -#define ClientReadBuffer_H - -#include "Control.h" -#include "ReadBuffer.h" - -class ClientChannel; - -class ClientReadBuffer : public ReadBuffer -{ - public: - - ClientReadBuffer(Transport *transport, ClientChannel *channel) - - : ReadBuffer(transport), firstMessage_(1), channel_(channel) - { - } - - virtual ~ClientReadBuffer() - { - } - - protected: - - virtual unsigned int suggestedLength(unsigned int pendingLength); - - virtual int locateMessage(const unsigned char *start, - const unsigned char *end, - unsigned int &controlLength, - unsigned int &dataLength, - unsigned int &trailerLength); - - int bigEndian_; - - int firstMessage_; - - ClientChannel *channel_; -}; - -#endif /* ClientReadBuffer_H */ diff --git a/nxcomp/ClientStore.cpp b/nxcomp/ClientStore.cpp deleted file mode 100644 index e1ba3f4a7..000000000 --- a/nxcomp/ClientStore.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ClientStore.h" - -// -// Cached request classes. -// - -#include "ChangeProperty.h" -#include "SendEvent.h" -#include "CreateGC.h" -#include "ChangeGC.h" -#include "CreatePixmap.h" -#include "SetClipRectangles.h" -#include "CopyArea.h" -#include "PolyLine.h" -#include "PolySegment.h" -#include "PolyFillRectangle.h" -#include "PutImage.h" -#include "TranslateCoords.h" -#include "GetImage.h" -#include "ClearArea.h" -#include "ConfigureWindow.h" -#include "ShapeExtension.h" -#include "RenderExtension.h" -#include "PolyText8.h" -#include "PolyText16.h" -#include "ImageText8.h" -#include "ImageText16.h" -#include "PolyPoint.h" -#include "PolyFillArc.h" -#include "PolyArc.h" -#include "FillPoly.h" -#include "InternAtom.h" -#include "GetProperty.h" -#include "SetUnpackGeometry.h" -#include "SetUnpackColormap.h" -#include "SetUnpackAlpha.h" -#include "PutPackedImage.h" -#include "GenericRequest.h" - -// -// Set the verbosity level. -// - -#define WARNING -#define PANIC -#undef TEST - -ClientStore::ClientStore(StaticCompressor *compressor) - - : compressor_(compressor) -{ - if (logofs == NULL) - { - logofs = &cout; - } - - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - requests_[i] = NULL; - } - - requests_[X_ChangeProperty] = new ChangePropertyStore(); - requests_[X_SendEvent] = new SendEventStore(); - requests_[X_CreateGC] = new CreateGCStore(); - requests_[X_SetClipRectangles] = new SetClipRectanglesStore(); - requests_[X_CopyArea] = new CopyAreaStore(); - requests_[X_PolyLine] = new PolyLineStore(); - requests_[X_PolySegment] = new PolySegmentStore(); - requests_[X_PolyFillRectangle] = new PolyFillRectangleStore(); - requests_[X_PutImage] = new PutImageStore(compressor); - requests_[X_TranslateCoords] = new TranslateCoordsStore(); - requests_[X_GetImage] = new GetImageStore(); - requests_[X_ClearArea] = new ClearAreaStore(); - requests_[X_ConfigureWindow] = new ConfigureWindowStore(); - requests_[X_PolyText8] = new PolyText8Store(); - requests_[X_PolyText16] = new PolyText16Store(); - requests_[X_ImageText8] = new ImageText8Store(); - requests_[X_ImageText16] = new ImageText16Store(); - requests_[X_PolyPoint] = new PolyPointStore(); - requests_[X_PolyFillArc] = new PolyFillArcStore(); - requests_[X_PolyArc] = new PolyArcStore(); - requests_[X_FillPoly] = new FillPolyStore(); - requests_[X_InternAtom] = new InternAtomStore(); - requests_[X_GetProperty] = new GetPropertyStore(); - - requests_[X_NXInternalShapeExtension] = new ShapeExtensionStore(compressor); - requests_[X_NXInternalGenericRequest] = new GenericRequestStore(compressor); - requests_[X_NXInternalRenderExtension] = new RenderExtensionStore(compressor); - requests_[X_NXSetUnpackGeometry] = new SetUnpackGeometryStore(compressor); - requests_[X_NXPutPackedImage] = new PutPackedImageStore(compressor); - - // Since ProtoStep7 (#issue 108) - requests_[X_ChangeGC] = new ChangeGCStore(); - requests_[X_CreatePixmap] = new CreatePixmapStore(); - requests_[X_NXSetUnpackColormap] = new SetUnpackColormapStore(compressor); - requests_[X_NXSetUnpackAlpha] = new SetUnpackAlphaStore(compressor); - - for (int i = 0; i < CHANNEL_STORE_RESOURCE_LIMIT; i++) - { - splits_[i] = NULL; - } - - commits_ = new CommitStore(compressor); -} - -ClientStore::~ClientStore() -{ - if (logofs == NULL) - { - logofs = &cout; - } - - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - delete requests_[i]; - } - - for (int i = 0; i < CHANNEL_STORE_RESOURCE_LIMIT; i++) - { - delete splits_[i]; - } - - delete commits_; -} - -int ClientStore::saveRequestStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient, T_checksum_action checksumAction, - T_data_action dataAction) const -{ - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - if (requests_[i] != NULL && - requests_[i] -> saveStore(cachefs, md5StateStream, md5StateClient, - checksumAction, dataAction, - storeBigEndian()) < 0) - { - #ifdef WARNING - *logofs << "ClientStore: WARNING! Error saving request store " - << "for OPCODE#" << (unsigned int) i << ".\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Error saving request store " - << "for opcode '" << (unsigned int) i << "'.\n"; - - return -1; - } - } - - return 1; -} - -int ClientStore::loadRequestStores(istream *cachefs, md5_state_t *md5StateStream, - T_checksum_action checksumAction, T_data_action dataAction) const -{ - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - if (requests_[i] != NULL && - requests_[i] -> loadStore(cachefs, md5StateStream, - checksumAction, dataAction, - storeBigEndian()) < 0) - { - #ifdef WARNING - *logofs << "ClientStore: WARNING! Error loading request store " - << "for OPCODE#" << (unsigned int) i << ".\n" - << logofs_flush; - #endif - - return -1; - } - } - - return 1; -} - -void ClientStore::dumpSplitStores() const -{ - for (int i = 0; i < CHANNEL_STORE_RESOURCE_LIMIT; i++) - { - if (splits_[i] != NULL) - { - splits_[i] -> dump(); - } - } - - if ((getSplitTotalSize() != 0 && getSplitTotalStorageSize() == 0) || - (getSplitTotalSize() == 0 && getSplitTotalStorageSize() != 0)) - { - #ifdef PANIC - *logofs << "ClientStore: PANIC! Inconsistency detected " - << "while handling the split stores.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } -} diff --git a/nxcomp/ClientStore.h b/nxcomp/ClientStore.h deleted file mode 100644 index 009d87d9f..000000000 --- a/nxcomp/ClientStore.h +++ /dev/null @@ -1,143 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ClientStore_H -#define ClientStore_H - -#include "Message.h" -#include "Split.h" - -#include "ChannelStore.h" - -class StaticCompressor; - -class ClientStore : public ChannelStore -{ - public: - - ClientStore(StaticCompressor *compressor); - - virtual ~ClientStore(); - - // - // Get the store based on the index. - // - - MessageStore *getRequestStore(unsigned char opcode) const - { - return requests_[opcode]; - } - - SplitStore *getSplitStore(int resource) const - { - return splits_[resource]; - } - - int getSplitTotalSize() const - { - return SplitStore::getTotalSize(); - } - - int getSplitTotalStorageSize() const - { - return SplitStore::getTotalStorageSize(); - } - - CommitStore *getCommitStore() const - { - return commits_; - } - - int getCommitSize() const - { - return commits_ -> getSize(); - } - - void dumpSplitStore(int resource) const - { - splits_[resource] -> dump(); - } - - void dumpCommitStore() const - { - commits_ -> dump(); - } - - void dumpSplitStores() const; - - SplitStore *createSplitStore(int resource) - { - splits_[resource] = new SplitStore(compressor_, commits_, resource); - - return splits_[resource]; - } - - void destroySplitStore(int resource) - { - delete splits_[resource]; - - splits_[resource] = NULL; - } - - // - // Actually save the message store - // to disk according to proxy mode. - // - - int saveRequestStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient, T_checksum_action checksumAction, - T_data_action dataAction) const; - - int loadRequestStores(istream *cachefs, md5_state_t *md5StateStream, - T_checksum_action checksumAction, T_data_action dataAction) const; - - private: - - // - // A client store contains requests. - // - - MessageStore *requests_[CHANNEL_STORE_OPCODE_LIMIT]; - - // - // Client messages being split. - // - - SplitStore *splits_[CHANNEL_STORE_RESOURCE_LIMIT]; - - // - // Messages having been recomposed. - // - - CommitStore *commits_; - - // - // Passed forward to the other stores. - // - - StaticCompressor *compressor_; -}; - -#endif /* ClientStore_H */ diff --git a/nxcomp/Colormap.cpp b/nxcomp/Colormap.cpp deleted file mode 100644 index 8579b7317..000000000 --- a/nxcomp/Colormap.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "Unpack.h" -#include "Colormap.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -int UnpackColormap(unsigned char method, unsigned char *src_data, int src_size, - unsigned char *dst_data, int dst_size) -{ - if (*src_data == 0) - { - if (dst_size != src_size - 1) - { - #ifdef TEST - *logofs << "UnpackColormap: PANIC! Invalid destination size " - << dst_size << " with source " << src_size - << ".\n" << logofs_flush; - #endif - - return -1; - } - - #ifdef TEST - *logofs << "UnpackColormap: Expanding " << src_size - 1 - << " bytes of plain colormap data.\n" << logofs_flush; - #endif - - memcpy(dst_data, src_data + 1, src_size - 1); - - return 1; - } - - unsigned int check_size = dst_size; - - int result = ZDecompress(&unpackStream, dst_data, &check_size, - src_data + 1, src_size - 1); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "UnpackColormap: PANIC! Failure decompressing colormap data. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decompressing colormap data. " - << "Error is '" << zError(result) << "'.\n"; - - return -1; - } - else if (check_size != (unsigned int) dst_size) - { - #ifdef PANIC - *logofs << "UnpackColormap: PANIC! Size mismatch in colormap data. " - << "Resulting size is " << check_size << " with " - << "expected size " << dst_size << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Size mismatch in colormap data. " - << "Resulting size is " << check_size << " with " - << "expected size " << dst_size << ".\n"; - - return -1; - } - - #ifdef TEST - *logofs << "UnpackColormap: Decompressed " << src_size - 1 - << " bytes to " << dst_size << " bytes of colormap data.\n" - << logofs_flush; - #endif - - return 1; -} diff --git a/nxcomp/Colormap.h b/nxcomp/Colormap.h deleted file mode 100644 index a96d003fa..000000000 --- a/nxcomp/Colormap.h +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Colormap_H -#define Colormap_H - -int UnpackColormap(unsigned char method, unsigned char *src_data, int src_size, - unsigned char *dst_data, int dst_size); - -#endif /* Colormap_H */ diff --git a/nxcomp/ConfigureWindow.cpp b/nxcomp/ConfigureWindow.cpp deleted file mode 100644 index 7b0794269..000000000 --- a/nxcomp/ConfigureWindow.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ConfigureWindow.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int ConfigureWindowStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ConfigureWindowMessage *configureWindow = (ConfigureWindowMessage *) message; - - // - // Here is the fingerprint. - // - - configureWindow -> window = GetULONG(buffer + 4, bigEndian); - - configureWindow -> value_mask = GetUINT(buffer + 8, bigEndian); - - // - // To increase effectiveness of the caching algorithm - // we remove the unused bytes carried in the data part. - // - - if ((int) size > dataOffset) - { - #ifdef DEBUG - *logofs << name() << ": Removing unused bytes from the data payload.\n" << logofs_flush; - #endif - - configureWindow -> value_mask &= (1 << 7) - 1; - - unsigned int mask = 0x1; - unsigned char *source = (unsigned char *) buffer + CONFIGUREWINDOW_DATA_OFFSET; - unsigned long value = 0; - - for (unsigned int i = 0; i < 7; i++) - { - if (configureWindow -> value_mask & mask) - { - value = GetULONG(source, bigEndian); - - value &= (1 << CONFIGUREWINDOW_FIELD_WIDTH[i]) - 1; - - PutULONG(value, source, bigEndian); - - source += 4; - } - mask <<= 1; - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int ConfigureWindowStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ConfigureWindowMessage *configureWindow = (ConfigureWindowMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(configureWindow -> window, buffer + 4, bigEndian); - - PutUINT(configureWindow -> value_mask, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void ConfigureWindowStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - ConfigureWindowMessage *configureWindow = (ConfigureWindowMessage *) message; - - *logofs << "ConfigureWindow: window " << configureWindow -> window - << ", value_mask " << configureWindow -> value_mask - << ", size " << configureWindow -> size_ << ".\n"; - - #endif -} - -void ConfigureWindowStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 4, 4); - md5_append(md5_state_, buffer + 8, 2); -} diff --git a/nxcomp/ConfigureWindow.h b/nxcomp/ConfigureWindow.h deleted file mode 100644 index e02c2aae1..000000000 --- a/nxcomp/ConfigureWindow.h +++ /dev/null @@ -1,178 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ConfigureWindow_H -#define ConfigureWindow_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define CONFIGUREWINDOW_ENABLE_CACHE 1 -#define CONFIGUREWINDOW_ENABLE_DATA 0 -#define CONFIGUREWINDOW_ENABLE_SPLIT 0 -#define CONFIGUREWINDOW_ENABLE_COMPRESS 0 - -#define CONFIGUREWINDOW_DATA_LIMIT 32 -#define CONFIGUREWINDOW_DATA_OFFSET 12 - -#define CONFIGUREWINDOW_CACHE_SLOTS 3000 -#define CONFIGUREWINDOW_CACHE_THRESHOLD 5 -#define CONFIGUREWINDOW_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class ConfigureWindowMessage : public Message -{ - friend class ConfigureWindowStore; - - public: - - ConfigureWindowMessage() - { - } - - ~ConfigureWindowMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int window; - unsigned short value_mask; -}; - -class ConfigureWindowStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - ConfigureWindowStore() : MessageStore() - { - enableCache = CONFIGUREWINDOW_ENABLE_CACHE; - enableData = CONFIGUREWINDOW_ENABLE_DATA; - enableSplit = CONFIGUREWINDOW_ENABLE_SPLIT; - enableCompress = CONFIGUREWINDOW_ENABLE_COMPRESS; - - dataLimit = CONFIGUREWINDOW_DATA_LIMIT; - dataOffset = CONFIGUREWINDOW_DATA_OFFSET; - - cacheSlots = CONFIGUREWINDOW_CACHE_SLOTS; - cacheThreshold = CONFIGUREWINDOW_CACHE_THRESHOLD; - cacheLowerThreshold = CONFIGUREWINDOW_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~ConfigureWindowStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "ConfigureWindow"; - } - - virtual unsigned char opcode() const - { - return X_ConfigureWindow; - } - - virtual unsigned int storage() const - { - return sizeof(ConfigureWindowMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new ConfigureWindowMessage(); - } - - virtual Message *create(const Message &message) const - { - return new ConfigureWindowMessage((const ConfigureWindowMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (ConfigureWindowMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* ConfigureWindow_H */ diff --git a/nxcomp/Control.cpp b/nxcomp/Control.cpp deleted file mode 100644 index 4469a9bf5..000000000 --- a/nxcomp/Control.cpp +++ /dev/null @@ -1,818 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "NX.h" -#include "NXpack.h" - -#include "Control.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Flush immediately on prioritized messages. -// - -#define FLUSH_PRIORITY 0 - -// -// Maximum number of bytes sent for each token. -// - -#define TOKEN_SIZE 1536 - -// -// Maximum number of tokens that can be spent -// by the client proxy before having to block -// waiting for a token reply. -// - -#define TOKEN_LIMIT 24 - -// -// By default assume the proxy is running as a -// standalone program. -// - -#define LINK_ENCRYPTED 0 - -// -// Maximum number of pids the proxy will record -// and kill at shutdown. -// - -#define KILL_LIMIT 16 - -// -// Allocate on the NX client side channels whose -// ids are a multiple of 8 (starting from 0). All -// the other ids can be used to allocate channels -// at the NX server side (X client side). -// - -#define CHANNEL_MASK 0x07 - -// -// Kill session if control parameters cannot be -// negotiated before this timeout. -// - -#define INIT_TIMEOUT 60000 - -// -// Enter the congestion state if the remote does -// not reply to a ping within the given amount -// of time. -// - -#define PING_TIMEOUT 5000 - -// -// Only send one motion event any N milliseconds. -// - -#define MOTION_TIMEOUT 0 - - -// -// Force an update of the congestion counter if -// the proxy is idle for this time. -// - -#define IDLE_TIMEOUT 50 - -// -// Close X connection if can't write before this -// timeout. -// - -#define CHANNEL_TIMEOUT 10000 - -// -// Warn user (or close proxy connection) if don't -// receive any data before this timeout. -// - -#define PROXY_TIMEOUT 120000 - -// -// How many milliseconds to wait for the shared -// memory completion event to become available. -// - -#define SHMEM_TIMEOUT 200 -// -// Before closing down the proxy, wait for the -// given amount of miliseconds to let all the -// running applications to close down their -// connections. -// -// A null timeout will cause the proxy to wait -// indefinitely, until the watchdog process is -// killed. This is usually the way the proxy is -// started by the NX server. If on the other -// hand a timeout is given and there no channel -// is remaining, the proxy will be closed down -// using a small timeout, presently of 500 ms. -// - -#define CLEANUP_TIMEOUT 3000 - -// -// Wait this amount of milliseconds after any -// iteration of the house-keeping process. -// - -#define KEEPER_TIMEOUT 60000 - -// -// In case of timeout, select can return control -// to program earlier or later of this amount of -// ms. Consider this when calculating if timeout -// is elapsed. -// - -#define LATENCY_TIMEOUT 1 - -// -// Control memory allocation in transport -// and other classes. -// - -#define TRANSPORT_X_BUFFER_SIZE 131072 -#define TRANSPORT_PROXY_BUFFER_SIZE 65536 -#define TRANSPORT_GENERIC_BUFFER_SIZE 16384 - -#define TRANSPORT_X_BUFFER_THRESHOLD 262144 -#define TRANSPORT_PROXY_BUFFER_THRESHOLD 131072 -#define TRANSPORT_GENERIC_BUFFER_THRESHOLD 32768 - -// -// Never allow buffers to exceed this limit. -// - -#define TRANSPORT_MAXIMUM_BUFFER_SIZE 393216 - -// -// Immediately flush the accumulated data to -// the X server if the write buffer exceeds -// this size. -// - -#define TRANSPORT_FLUSH_BUFFER_SIZE 16384 - -// -// Defaults used for socket options. -// - -#define OPTION_PROXY_KEEP_ALIVE 0 -#define OPTION_PROXY_LOW_DELAY 1 -#define OPTION_PROXY_CLIENT_NO_DELAY 1 -#define OPTION_PROXY_SERVER_NO_DELAY 1 -#define OPTION_CLIENT_NO_DELAY 1 -#define OPTION_SERVER_NO_DELAY 1 - -#define OPTION_PROXY_RECEIVE_BUFFER -1 -#define OPTION_CLIENT_RECEIVE_BUFFER -1 -#define OPTION_SERVER_RECEIVE_BUFFER -1 - -#define OPTION_PROXY_SEND_BUFFER -1 -#define OPTION_CLIENT_SEND_BUFFER -1 -#define OPTION_SERVER_SEND_BUFFER -1 - -#define OPTION_PROXY_RETRY_CONNECT 30 -#define OPTION_PROXY_RETRY_ACCEPT 3 -#define OPTION_SERVER_RETRY_CONNECT 3 - -// -// Defaults used for cache persistence. -// - -#define PERSISTENT_CACHE_THRESHOLD 102400 - -#define PERSISTENT_CACHE_ENABLE_LOAD 1 -#define PERSISTENT_CACHE_ENABLE_SAVE 1 - -#define PERSISTENT_CACHE_CHECK_ON_SHUTDOWN 0 - -#define PERSISTENT_CACHE_LOAD_PACKED 1 -#define PERSISTENT_CACHE_LOAD_RENDER 1 - -#define PERSISTENT_CACHE_DISK_LIMIT 33554432 - -// -// Defaults used for image cache. -// - -#define IMAGE_CACHE_ENABLE_LOAD 0 -#define IMAGE_CACHE_ENABLE_SAVE 0 - -#define IMAGE_CACHE_DISK_LIMIT 33554432 - -// -// Suggested defaults for read length parameters -// used by read buffer classes. -// - -#define CLIENT_INITIAL_READ_SIZE 8192 -#define CLIENT_MAXIMUM_BUFFER_SIZE 262144 - -#define SERVER_INITIAL_READ_SIZE 8192 -#define SERVER_MAXIMUM_BUFFER_SIZE 65536 - -#define PROXY_INITIAL_READ_SIZE 65536 -#define PROXY_MAXIMUM_BUFFER_SIZE 262144 + 1024 - -#define GENERIC_INITIAL_READ_SIZE 8192 -#define GENERIC_MAXIMUM_BUFFER_SIZE 8192 - -// -// Calculate bitrate in given time frames. -// Values are in milliseconds. -// - -#define SHORT_BITRATE_TIME_FRAME 5000 -#define LONG_BITRATE_TIME_FRAME 30000 - -// -// Bandwidth control. A value of 0 means no -// limit. Values are stored internally in -// bytes per second. -// - -#define CLIENT_BITRATE_LIMIT 0 -#define SERVER_BITRATE_LIMIT 0 - -// -// Default values for cache control. We limit -// the maximum size of a request to 262144 but -// we need to consider the replies, whose size -// may be up to 4MB. -// - -#define MINIMUM_MESSAGE_SIZE 4 -#define MAXIMUM_MESSAGE_SIZE 4194304 -#define MAXIMUM_REQUEST_SIZE 262144 - -#define CLIENT_TOTAL_STORAGE_SIZE 8388608 -#define SERVER_TOTAL_STORAGE_SIZE 8388608 - -#define STORE_TIME_LIMIT 3600 - -#define STORE_HITS_LOAD_BONUS 10 -#define STORE_HITS_ADD_BONUS 20 -#define STORE_HITS_LIMIT 100 - -#define STORE_HITS_TOUCH 1 -#define STORE_HITS_UNTOUCH 2 - -// -// Default parameters for message splitting. -// - -#define SPLIT_MODE 1 -#define SPLIT_TIMEOUT 50 -#define SPLIT_TOTAL_SIZE 128 -#define SPLIT_TOTAL_STORAGE_SIZE 1048576 -#define SPLIT_DATA_THRESHOLD 65536 -#define SPLIT_DATA_PACKET_LIMIT 24576 - -// -// Agent related parameters. -// - -#define PACK_METHOD 63 -#define PACK_QUALITY 9 -#define HIDE_RENDER 0 -#define TAINT_REPLIES 1 -#define TAINT_THRESHOLD 8 - -// -// In current version only X server support is -// implemented. Note that use of shared memory -// is negotiated according to options provided -// by the user. -// - -#define SHMEM_CLIENT 0 -#define SHMEM_SERVER 1 - -// -// Default size of shared memory segments used -// in MIT-SHM support. -// - -#define SHMEM_CLIENT_SIZE 0 -#define SHMEM_SERVER_SIZE 2097152 - -// -// What do we do at the end of session? If this -// flag is set, we launch a new client letting -// the user run a new NX session. -// - -#define ENABLE_RESTART_ON_SHUTDOWN 0 - -// -// Do we produce a core dump on fatal errors? -// - -#define ENABLE_CORE_DUMP_ON_ABORT 0 - -// -// Reopen the log file if it exceeds this size. -// - -#define FILE_SIZE_LIMIT 60000000 - -// -// Check periodically if we need to truncate the -// log file. By default check every minute. -// - -#define FILE_SIZE_CHECK_TIMEOUT 60000 - -// -// Protocol version compatibility values -// - -const int Control::NX_MIN_PROTO_STEP = 10; -const int Control::NX_MAX_PROTO_STEP = 10; -const char* const Control::NXPROXY_COMPATIBILITY_VERSION = "3.5.0"; - -// -// Set defaults for control. They should be what -// you get in case of 'local' connection. -// - -Control::Control() -{ - ProxyMode = proxy_undefined; - ProxyStage = stage_undefined; - SessionMode = session_undefined; - FlushPolicy = policy_undefined; - LinkMode = link_undefined; - - LinkEncrypted = LINK_ENCRYPTED; - FlushPriority = FLUSH_PRIORITY; - - TokenSize = TOKEN_SIZE; - TokenLimit = TOKEN_LIMIT; - - ChannelMask = CHANNEL_MASK; - - InitTimeout = INIT_TIMEOUT; - PingTimeout = PING_TIMEOUT; - MotionTimeout = MOTION_TIMEOUT; - IdleTimeout = IDLE_TIMEOUT; - - ChannelTimeout = CHANNEL_TIMEOUT; - ProxyTimeout = PROXY_TIMEOUT; - ShmemTimeout = SHMEM_TIMEOUT; - - CleanupTimeout = CLEANUP_TIMEOUT; - KeeperTimeout = KEEPER_TIMEOUT; - LatencyTimeout = LATENCY_TIMEOUT; - - FileSizeLimit = FILE_SIZE_LIMIT; - FileSizeCheckTimeout = FILE_SIZE_CHECK_TIMEOUT; - - EnableRestartOnShutdown = ENABLE_RESTART_ON_SHUTDOWN; - - KillDaemonOnShutdownLimit = KILL_LIMIT; - - KillDaemonOnShutdown = new int[KillDaemonOnShutdownLimit]; - - for (int i = 0; i < KILL_LIMIT; i++) - { - KillDaemonOnShutdown[i] = -1; - } - - KillDaemonOnShutdownNumber = 0; - - EnableCoreDumpOnAbort = ENABLE_CORE_DUMP_ON_ABORT; - - // - // Collect statistics by default. - // - - EnableStatistics = 1; - - // - // Memory restrictions if any. - // - - LocalMemoryLevel = -1; - - // - // Compression must be negotiated between proxies. - // - - LocalDeltaCompression = -1; - RemoteDeltaCompression = -1; - - LocalDataCompression = -1; - LocalStreamCompression = -1; - - RemoteDataCompression = -1; - RemoteStreamCompression = -1; - - LocalDataCompressionLevel = -1; - LocalDataCompressionThreshold = -1; - LocalStreamCompressionLevel = -1; - - RemoteDataCompressionLevel = -1; - RemoteStreamCompressionLevel = -1; - - // - // Transport buffers' allocation parameters. - // - - TransportXBufferSize = TRANSPORT_X_BUFFER_SIZE; - TransportProxyBufferSize = TRANSPORT_PROXY_BUFFER_SIZE; - TransportGenericBufferSize = TRANSPORT_GENERIC_BUFFER_SIZE; - - TransportXBufferThreshold = TRANSPORT_X_BUFFER_THRESHOLD; - TransportProxyBufferThreshold = TRANSPORT_PROXY_BUFFER_THRESHOLD; - TransportGenericBufferThreshold = TRANSPORT_GENERIC_BUFFER_THRESHOLD; - - TransportMaximumBufferSize = TRANSPORT_MAXIMUM_BUFFER_SIZE; - - // - // Flush the write buffer if it exceeds - // this size. - // - - TransportFlushBufferSize = TRANSPORT_FLUSH_BUFFER_SIZE; - - // - // Socket options. - // - - OptionProxyKeepAlive = OPTION_PROXY_KEEP_ALIVE; - OptionProxyLowDelay = OPTION_PROXY_LOW_DELAY; - OptionProxyClientNoDelay = OPTION_PROXY_CLIENT_NO_DELAY; - OptionProxyServerNoDelay = OPTION_PROXY_SERVER_NO_DELAY; - OptionClientNoDelay = OPTION_CLIENT_NO_DELAY; - OptionServerNoDelay = OPTION_SERVER_NO_DELAY; - - OptionProxyReceiveBuffer = OPTION_PROXY_RECEIVE_BUFFER; - OptionClientReceiveBuffer = OPTION_CLIENT_RECEIVE_BUFFER; - OptionServerReceiveBuffer = OPTION_SERVER_RECEIVE_BUFFER; - - OptionProxySendBuffer = OPTION_PROXY_SEND_BUFFER; - OptionClientSendBuffer = OPTION_CLIENT_SEND_BUFFER; - OptionServerSendBuffer = OPTION_SERVER_SEND_BUFFER; - - OptionProxyRetryAccept = OPTION_PROXY_RETRY_ACCEPT; - OptionProxyRetryConnect = OPTION_PROXY_RETRY_CONNECT; - OptionServerRetryConnect = OPTION_SERVER_RETRY_CONNECT; - - // - // Base NX directories. - // - - HomePath = NULL; - RootPath = NULL; - SystemPath = NULL; - TempPath = NULL; - ClientPath = NULL; - - // - // Set defaults for handling persistent cache. - // - - PersistentCachePath = NULL; - PersistentCacheName = NULL; - - PersistentCacheThreshold = PERSISTENT_CACHE_THRESHOLD; - - PersistentCacheEnableLoad = PERSISTENT_CACHE_ENABLE_LOAD; - PersistentCacheEnableSave = PERSISTENT_CACHE_ENABLE_SAVE; - - PersistentCacheCheckOnShutdown = PERSISTENT_CACHE_CHECK_ON_SHUTDOWN; - - PersistentCacheLoadPacked = PERSISTENT_CACHE_LOAD_PACKED; - PersistentCacheLoadRender = PERSISTENT_CACHE_LOAD_RENDER; - - PersistentCacheDiskLimit = PERSISTENT_CACHE_DISK_LIMIT; - - // - // Set defaults for image cache. - // - - ImageCachePath = NULL; - - ImageCacheEnableLoad = IMAGE_CACHE_ENABLE_LOAD; - ImageCacheEnableSave = IMAGE_CACHE_ENABLE_SAVE; - - ImageCacheDiskLimit = IMAGE_CACHE_DISK_LIMIT; - - // - // Set defaults for the read buffers. - // - - ClientInitialReadSize = CLIENT_INITIAL_READ_SIZE; - ClientMaximumBufferSize = CLIENT_MAXIMUM_BUFFER_SIZE; - - ServerInitialReadSize = SERVER_INITIAL_READ_SIZE; - ServerMaximumBufferSize = SERVER_MAXIMUM_BUFFER_SIZE; - - ProxyInitialReadSize = PROXY_INITIAL_READ_SIZE; - ProxyMaximumBufferSize = PROXY_MAXIMUM_BUFFER_SIZE; - - GenericInitialReadSize = GENERIC_INITIAL_READ_SIZE; - GenericMaximumBufferSize = GENERIC_MAXIMUM_BUFFER_SIZE; - - ShortBitrateTimeFrame = SHORT_BITRATE_TIME_FRAME; - LongBitrateTimeFrame = LONG_BITRATE_TIME_FRAME; - - // - // Bandwidth control. - // - - LocalBitrateLimit = -1; - - ClientBitrateLimit = CLIENT_BITRATE_LIMIT; - ServerBitrateLimit = SERVER_BITRATE_LIMIT; - - // - // Default parameters for message handling. - // - - ClientTotalStorageSize = CLIENT_TOTAL_STORAGE_SIZE; - ServerTotalStorageSize = SERVER_TOTAL_STORAGE_SIZE; - - LocalTotalStorageSize = -1; - RemoteTotalStorageSize = -1; - - StoreTimeLimit = STORE_TIME_LIMIT; - - StoreHitsLoadBonus = STORE_HITS_LOAD_BONUS; - StoreHitsAddBonus = STORE_HITS_ADD_BONUS; - StoreHitsLimit = STORE_HITS_LIMIT; - - StoreHitsTouch = STORE_HITS_TOUCH; - StoreHitsUntouch = STORE_HITS_UNTOUCH; - - MinimumMessageSize = MINIMUM_MESSAGE_SIZE; - MaximumMessageSize = MAXIMUM_MESSAGE_SIZE; - MaximumRequestSize = MAXIMUM_REQUEST_SIZE; - - SplitMode = SPLIT_MODE; - SplitTimeout = SPLIT_TIMEOUT; - SplitTotalSize = SPLIT_TOTAL_SIZE; - SplitTotalStorageSize = SPLIT_TOTAL_STORAGE_SIZE; - SplitDataThreshold = SPLIT_DATA_THRESHOLD; - SplitDataPacketLimit = SPLIT_DATA_PACKET_LIMIT; - - PackMethod = PACK_METHOD; - PackQuality = PACK_QUALITY; - HideRender = HIDE_RENDER; - TaintReplies = TAINT_REPLIES; - TaintThreshold = TAINT_THRESHOLD; - - ShmemClient = SHMEM_CLIENT; - ShmemServer = SHMEM_SERVER; - - ShmemClientSize = SHMEM_CLIENT_SIZE; - ShmemServerSize = SHMEM_SERVER_SIZE; - - // - // Get local version number from compile time - // settings. Version of remote proxy will be - // checked at connection time. - // - - RemoteVersionMajor = -1; - RemoteVersionMinor = -1; - RemoteVersionPatch = -1; - RemoteVersionMaintenancePatch = -1; - - CompatVersionMajor = -1; - CompatVersionMinor = -1; - CompatVersionPatch = -1; - CompatVersionMaintenancePatch = -1; - - LocalVersionMajor = NXMajorVersion(); - LocalVersionMinor = NXMinorVersion(); - LocalVersionPatch = NXPatchVersion(); - LocalVersionMaintenancePatch = NXMaintenancePatchVersion(); - - #ifdef TEST - *logofs << "Control: Major version is " << LocalVersionMajor - << " minor is " << LocalVersionMinor << " patch is " - << LocalVersionPatch << " Maintenance version is " - << LocalVersionMaintenancePatch << ".\n" << logofs_flush; - #endif - - // - // Initialize local implemented methods later - // and negotiate remote methods at connection - // time. - // - - LocalUnpackMethods = NULL; - RemoteUnpackMethods = NULL; - - // - // Set to 1 those methods which are implemented. - // - - setLocalUnpackMethods(); - - // - // Set the protocol version at the - // time the session is negotiated. - // - - protoStep_ = 0; -} - -Control::~Control() -{ - if (KillDaemonOnShutdown != NULL) - { - delete [] KillDaemonOnShutdown; - } - - if (HomePath != NULL) - { - delete [] HomePath; - } - - if (RootPath != NULL) - { - delete [] RootPath; - } - - if (SystemPath != NULL) - { - delete [] SystemPath; - } - - if (TempPath != NULL) - { - delete [] TempPath; - } - - if (ClientPath != NULL) - { - delete [] ClientPath; - } - - if (PersistentCachePath != NULL) - { - delete [] PersistentCachePath; - } - - if (PersistentCacheName != NULL) - { - delete [] PersistentCacheName; - } - - if (LocalUnpackMethods != NULL) - { - delete [] LocalUnpackMethods; - } - - if (RemoteUnpackMethods != NULL) - { - delete [] RemoteUnpackMethods; - } - - if (ImageCachePath != NULL) - { - delete [] ImageCachePath; - } -} - -// -// Set the protocol step based on the -// remote version. -// - -void Control::setProtoStep(int step) -{ - if (isValidProtoStep(step)) - { - protoStep_ = step; - } - else - { - #ifdef PANIC - *logofs << "Control: PANIC! Invalid protocol step " - << "with value " << step << ".\n" - << logofs_flush; - #endif - - HandleCleanup(); - } -} - -int Control::getProtoStep() -{ - if (isValidProtoStep(protoStep_)) - { - return protoStep_; - } - else - { - #ifdef PANIC - *logofs << "Control: PANIC! Can't identify the " - << "protocol step.\n" << logofs_flush; - #endif - - HandleCleanup(); - } -} - -// -// Set here the pack/unpack methods that are -// implemented by this NX proxy. -// - -void Control::setLocalUnpackMethods() -{ - LocalUnpackMethods = new unsigned char[PACK_METHOD_LIMIT]; - RemoteUnpackMethods = new unsigned char[PACK_METHOD_LIMIT]; - - for (int i = 0; i < PACK_METHOD_LIMIT; i++) - { - LocalUnpackMethods[i] = 0; - RemoteUnpackMethods[i] = 0; - } - - LocalUnpackMethods[NO_PACK] = 1; - - LocalUnpackMethods[PACK_MASKED_8_COLORS] = 1; - LocalUnpackMethods[PACK_MASKED_64_COLORS] = 1; - LocalUnpackMethods[PACK_MASKED_256_COLORS] = 1; - LocalUnpackMethods[PACK_MASKED_512_COLORS] = 1; - LocalUnpackMethods[PACK_MASKED_4K_COLORS] = 1; - LocalUnpackMethods[PACK_MASKED_32K_COLORS] = 1; - LocalUnpackMethods[PACK_MASKED_64K_COLORS] = 1; - LocalUnpackMethods[PACK_MASKED_256K_COLORS] = 1; - LocalUnpackMethods[PACK_MASKED_2M_COLORS] = 1; - LocalUnpackMethods[PACK_MASKED_16M_COLORS] = 1; - - LocalUnpackMethods[PACK_RAW_8_BITS] = 1; - LocalUnpackMethods[PACK_RAW_16_BITS] = 1; - LocalUnpackMethods[PACK_RAW_24_BITS] = 1; - - LocalUnpackMethods[PACK_COLORMAP_256_COLORS] = 1; - - LocalUnpackMethods[PACK_JPEG_8_COLORS] = 1; - LocalUnpackMethods[PACK_JPEG_64_COLORS] = 1; - LocalUnpackMethods[PACK_JPEG_256_COLORS] = 1; - LocalUnpackMethods[PACK_JPEG_512_COLORS] = 1; - LocalUnpackMethods[PACK_JPEG_4K_COLORS] = 1; - LocalUnpackMethods[PACK_JPEG_32K_COLORS] = 1; - LocalUnpackMethods[PACK_JPEG_64K_COLORS] = 1; - LocalUnpackMethods[PACK_JPEG_256K_COLORS] = 1; - LocalUnpackMethods[PACK_JPEG_2M_COLORS] = 1; - LocalUnpackMethods[PACK_JPEG_16M_COLORS] = 1; - - LocalUnpackMethods[PACK_PNG_8_COLORS] = 1; - LocalUnpackMethods[PACK_PNG_64_COLORS] = 1; - LocalUnpackMethods[PACK_PNG_256_COLORS] = 1; - LocalUnpackMethods[PACK_PNG_512_COLORS] = 1; - LocalUnpackMethods[PACK_PNG_4K_COLORS] = 1; - LocalUnpackMethods[PACK_PNG_32K_COLORS] = 1; - LocalUnpackMethods[PACK_PNG_64K_COLORS] = 1; - LocalUnpackMethods[PACK_PNG_256K_COLORS] = 1; - LocalUnpackMethods[PACK_PNG_2M_COLORS] = 1; - LocalUnpackMethods[PACK_PNG_16M_COLORS] = 1; - - LocalUnpackMethods[PACK_RGB_16M_COLORS] = 1; - LocalUnpackMethods[PACK_RLE_16M_COLORS] = 1; - - LocalUnpackMethods[PACK_ALPHA] = 1; - LocalUnpackMethods[PACK_COLORMAP] = 1; - - LocalUnpackMethods[PACK_BITMAP_16M_COLORS] = 1; -} diff --git a/nxcomp/Control.h b/nxcomp/Control.h deleted file mode 100644 index 764fca2c1..000000000 --- a/nxcomp/Control.h +++ /dev/null @@ -1,764 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Control_H -#define Control_H - -#include "NXpack.h" - -#include "Misc.h" -#include "Types.h" -#include "Timestamp.h" -#include "Statistics.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// This is the mode proxy is running. -// - -typedef enum -{ - proxy_undefined = -1, - proxy_client, - proxy_server, - proxy_last_tag -} -T_proxy_mode; - -// -// Handle advances in the connection -// procedure. -// - -typedef enum -{ - stage_undefined, - stage_initializing, - stage_connecting, - stage_connected, - stage_waiting_forwarder_version, - stage_waiting_forwarder_options, - stage_sending_forwarder_options, - stage_waiting_proxy_version, - stage_waiting_proxy_options, - stage_sending_proxy_options, - stage_waiting_proxy_caches, - stage_sending_proxy_caches, - stage_operational, - stage_terminating, - stage_terminated -} -T_proxy_stage; - -// -// Hint about whether or not the proxy is -// connected to a NX agen. -// - -typedef enum -{ - session_undefined = -1, - session_agent, - session_shadow, - session_proxy, - session_last_tag -} -T_session_mode; - -// -// Set how data will be written to the peer -// socket. -// - -typedef enum -{ - policy_undefined = -1, - policy_immediate, - policy_deferred -} -T_flush_policy; - -// -// Link mode, after negotiation, will be set to -// any of the values defined in the NXproto.h. -// - -#define link_undefined -1; - -// -// This class collects functioning parameters, -// to be configurable at run-time. They are for -// the most part regarding timeouts, transport -// and message stores handling. -// - -class Control -{ - public: - - // - // Does proxy run in client mode or server mode? - // As soon as we'll have gone through parsing of - // the command line options the current mode will - // be propagated to the control class. - // - - T_proxy_mode ProxyMode; - - // - // Goes from initializing to operational. - // - - T_proxy_stage ProxyStage; - - // - // Hint about type of session currently running. - // - - T_session_mode SessionMode; - - // - // Either immediate or defferred flushes. - // - - T_flush_policy FlushPolicy; - - // - // If set, the channels will try to flush the - // encoded data whenever there is a prioritized - // message. Depending on the flush policy, this - // may determine an immediate flush or an event - // being generated telling to the agent that it - // should flush the proxy link. - // - - int FlushPriority; - - // - // Id corresponding to link speed negotiated - // between proxies. - // - - int LinkMode; - - // - // Set if the proxy is connected to a program - // providing the encryption of the point to - // point communication. - // - - int LinkEncrypted; - - // - // Maximum number of bytes sent for each token. - // - - int TokenSize; - - // - // Maximum number of tokens that can be spent - // by the client proxy before having to block - // waiting for a reply. - // - - int TokenLimit; - - // - // Bitmask used to determine the distribution - // of channel ids between the client and server - // proxies. - // - - int ChannelMask; - - // - // Kill session if control parameters cannot - // be negotiated before this timeout. - // - - int InitTimeout; - - // - // Enter the congestion state if the remote does - // not reply to the ping within the given amount - // of time. - // - - int PingTimeout; - - // - // Enqueue motion notify events in server channel. - // - - int MotionTimeout; - - // - // Force an update of the congestion counter if - // the proxy is idle for this time. - // - - int IdleTimeout; - - // - // Close the connection if can't write before - // this timeout. - // - - int ChannelTimeout; - - // - // Close connection if can't write before - // this timeout. - // - - int ProxyTimeout; - - // - // How many milliseconds to wait for the shared - // memory completion event to become available. - // - - int ShmemTimeout; - - // - // Wait for applications to complete at the time - // proxy is shut down. - // - - int CleanupTimeout; - - // - // Wait this amount of milliseconds before any - // iteration of the house-keeping process. - // - - int KeeperTimeout; - - // - // Adjust timeout calculations. - // - - int LatencyTimeout; - - // - // Maximum allowed size of log files. - // - - int FileSizeLimit; - int FileSizeCheckTimeout; - - // - // What do we do at the end of session? If - // this flag is set we launch a new client - // letting the user run a new NX session. - // - - int EnableRestartOnShutdown; - - // - // The client can request the proxy to kill - // a number of processes before exiting. - // - - int *KillDaemonOnShutdown; - int KillDaemonOnShutdownNumber; - int KillDaemonOnShutdownLimit; - - // - // Do we generate a core dump and exit in - // case of program errors? - // - - int EnableCoreDumpOnAbort; - - // - // Is statistic output enabled? - // - - int EnableStatistics; - - // - // Version number of local and remote proxy. - // - - /* - * LocalVersionMaintenancePatch, RemoteVersionMaintenancePatch - * CompatVersionMaintenancePatch - * - * currently not used, for future compatibility checks - */ - int LocalVersionMajor; - int LocalVersionMinor; - int LocalVersionPatch; - int LocalVersionMaintenancePatch; - - int RemoteVersionMajor; - int RemoteVersionMinor; - int RemoteVersionPatch; - int RemoteVersionMaintenancePatch; - - int CompatVersionMajor; - int CompatVersionMinor; - int CompatVersionPatch; - int CompatVersionMaintenancePatch; - - // - // Compatibility version for the proxy - // - - static const char* const NXPROXY_COMPATIBILITY_VERSION; - - // - // Which unpack methods are implemented in proxy? - // - - unsigned char *LocalUnpackMethods; - unsigned char *RemoteUnpackMethods; - - // - // Memory restriction imposed by user. - // - - int LocalMemoryLevel; - - // - // Use or not differential compression - // and caching of X protocol messages. - // - - int LocalDeltaCompression; - int RemoteDeltaCompression; - - // - // Compression of images and replies. - // - - int LocalDataCompression; - int LocalDataCompressionLevel; - - int RemoteDataCompression; - int RemoteDataCompressionLevel; - - // - // Minimum packet size to be compressed. - // - - int LocalDataCompressionThreshold; - - // - // Compress or not data flowing through the proxy - // link. Level should be one of the ZLIB level as - // Z_DEFAULT_COMPRESSION or Z_BEST_COMPRESSION. - // - - int LocalStreamCompression; - int LocalStreamCompressionLevel; - - int RemoteStreamCompression; - int RemoteStreamCompressionLevel; - - // - // Size of read operations in read buffer classes. - // - - int ClientInitialReadSize; - int ClientMaximumBufferSize; - - int ServerInitialReadSize; - int ServerMaximumBufferSize; - - int ProxyInitialReadSize; - int ProxyMaximumBufferSize; - - int GenericInitialReadSize; - int GenericMaximumBufferSize; - - // - // Set initial size and resize policy of - // transport buffers. If maximum size is - // exceeded, print a warning. - // - - int TransportXBufferSize; - int TransportProxyBufferSize; - int TransportGenericBufferSize; - - int TransportXBufferThreshold; - int TransportProxyBufferThreshold; - int TransportGenericBufferThreshold; - - int TransportMaximumBufferSize; - - // - // Flush the data produced for the channel - // connection if it exceeds this size. - // - - int TransportFlushBufferSize; - - // - // Socket options. - // - - int OptionProxyKeepAlive; - int OptionProxyLowDelay; - int OptionProxyClientNoDelay; - int OptionProxyServerNoDelay; - int OptionClientNoDelay; - int OptionServerNoDelay; - - int OptionProxyReceiveBuffer; - int OptionClientReceiveBuffer; - int OptionServerReceiveBuffer; - - int OptionProxySendBuffer; - int OptionClientSendBuffer; - int OptionServerSendBuffer; - - int OptionProxyRetryAccept; - int OptionProxyRetryConnect; - int OptionServerRetryConnect; - - // - // Calculate current bitrate on proxy link - // using these observation periods. Value - // is in milliseconds. - // - - int ShortBitrateTimeFrame; - int LongBitrateTimeFrame; - - // - // Limit the bandwidth usage of the proxy - // link. - // - - int LocalBitrateLimit; - - int ClientBitrateLimit; - int ServerBitrateLimit; - - // - // This is the limit imposed by user on - // total cache size. - // - - int ClientTotalStorageSize; - int ServerTotalStorageSize; - - int LocalTotalStorageSize; - int RemoteTotalStorageSize; - - // - // Discard messages in store older than - // this amount of seconds. - // - - int StoreTimeLimit; - - // - // Any new message in store starts with - // this amount of hits. - // - - int StoreHitsAddBonus; - - // - // Unless it is loaded from persistent - // cache. - // - - int StoreHitsLoadBonus; - - // - // Stop increasing hits at this threshold. - // - - int StoreHitsLimit; - - // - // Give a special weight to messages put or - // taken from cache during startup time. - // - - int StoreHitsStartup; - - // - // Weight of touch and untoch operations. - // - - int StoreHitsTouch; - int StoreHitsUntouch; - - // - // Directives on size of messages to cache. - // - - int MinimumMessageSize; - int MaximumMessageSize; - - // - // Maximum size of a single X request. - // - - int MaximumRequestSize; - - // - // Currently selected streaming mode. - // - - int SplitMode; - - // - // Send new split data any given amount of - // milliseconds. - // - - int SplitTimeout; - - // - // Maximum number of distinct messages and - // maximum size in bytes of the temporary - // storage. - // - - int SplitTotalSize; - int SplitTotalStorageSize; - - // - // Don't split messages smaller that this - // threshold and send no more than the - // given amount of bytes in a single data - // shot when streaming the split messages. - // - - int SplitDataThreshold; - int SplitDataPacketLimit; - - // - // Agent related parameters. These values apply - // to the agent which, at startup, must query - // the user's settings. - // - - int PackMethod; - int PackQuality; - int HideRender; - int TaintReplies; - int TaintThreshold; - - // - // Do we allow shared memory image support in - // client and or server? - // - - int ShmemClient; - int ShmemServer; - - // - // Default size of shared memory segments used - // in MIT-SHM support. - // - - int ShmemClientSize; - int ShmemServerSize; - - // - // The user's home directory. - // - - char *HomePath; - - // - // The ".nx" directory, usually in - // the user's home. - // - - char *RootPath; - - // - // Usually the /usr/NX" directory. - // - - char *SystemPath; - - // - // Usually the "/tmp" directory. - // - - char *TempPath; - - // - // The complete path to the client. - // - - char *ClientPath; - - // - // String containing path of cache - // file selected for load or save. - // - - char *PersistentCachePath; - - // - // Name of selected cache file. - // - - char *PersistentCacheName; - - // - // Minimum size of cache in memory - // to proceed to its storage on disk. - // - - int PersistentCacheThreshold; - - // - // Is persistent cache enabled? - // - - int PersistentCacheEnableLoad; - int PersistentCacheEnableSave; - - // - // This is used just for test because - // it requires that client and server - // reside on the same machine. - // - - int PersistentCacheCheckOnShutdown; - - // - // Load packed image and render extension - // message stores. This currently depends - // on the type of session. - // - - int PersistentCacheLoadPacked; - int PersistentCacheLoadRender; - - // - // Maximum disk consumption of message - // caches on disk. - // - - int PersistentCacheDiskLimit; - - // - // String containing the base path - // of image cache files. - // - - char *ImageCachePath; - - // - // Is image cache enabled? - // - - int ImageCacheEnableLoad; - int ImageCacheEnableSave; - - // - // Maximum disk consumption of image - // caches on disk. - // - - int ImageCacheDiskLimit; - - // - // Only constructor, destructor - // and a few utility functions. - // - - Control(); - - ~Control(); - - // - // Should not leverage control to find channel - // stores' size limits. As most of values in - // control, this info must be moved elsewhere. - // - - int getUpperStorageSize() const - { - return (ClientTotalStorageSize > - ServerTotalStorageSize ? - ClientTotalStorageSize : - ServerTotalStorageSize); - } - - int getLowerStorageSize() const - { - return (ClientTotalStorageSize < - ServerTotalStorageSize ? - ClientTotalStorageSize : - ServerTotalStorageSize); - } - - void setProtoStep(int step); - - int getProtoStep(); - - private: - - // - // Look in Control.cpp. - // - - void setLocalUnpackMethods(); - - // - // Manage the encoding according - // to the protocol version. - // - - int protoStep_; - - // - // Min and max values allowed for protocol step - // depending on protocol version compatibility - // - - static const int NX_MIN_PROTO_STEP; - static const int NX_MAX_PROTO_STEP; - - // - // Check the validity of protocol step - // - - bool isValidProtoStep(int step) - { - return ((step >= NX_MIN_PROTO_STEP) && (step <= NX_MAX_PROTO_STEP)); - } - -}; - -#endif /* Control_H */ diff --git a/nxcomp/CopyArea.cpp b/nxcomp/CopyArea.cpp deleted file mode 100644 index 3bff8d60e..000000000 --- a/nxcomp/CopyArea.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "CopyArea.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -int CopyAreaStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - CopyAreaMessage *copyArea = (CopyAreaMessage *) message; - - // - // Here is the fingerprint. - // - - copyArea -> src_drawable = GetULONG(buffer + 4, bigEndian); - copyArea -> dst_drawable = GetULONG(buffer + 8, bigEndian); - copyArea -> gcontext = GetULONG(buffer + 12, bigEndian); - - copyArea -> src_x = GetUINT(buffer + 16, bigEndian); - copyArea -> src_y = GetUINT(buffer + 18, bigEndian); - copyArea -> dst_x = GetUINT(buffer + 20, bigEndian); - copyArea -> dst_y = GetUINT(buffer + 22, bigEndian); - - copyArea -> width = GetUINT(buffer + 24, bigEndian); - copyArea -> height = GetUINT(buffer + 26, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int CopyAreaStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - CopyAreaMessage *copyArea = (CopyAreaMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(copyArea -> src_drawable, buffer + 4, bigEndian); - PutULONG(copyArea -> dst_drawable, buffer + 8, bigEndian); - PutULONG(copyArea -> gcontext, buffer + 12, bigEndian); - - PutUINT(copyArea -> src_x, buffer + 16, bigEndian); - PutUINT(copyArea -> src_y, buffer + 18, bigEndian); - PutUINT(copyArea -> dst_x, buffer + 20, bigEndian); - PutUINT(copyArea -> dst_y, buffer + 22, bigEndian); - - PutUINT(copyArea -> width, buffer + 24, bigEndian); - PutUINT(copyArea -> height, buffer + 26, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void CopyAreaStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - CopyAreaMessage *copyArea = (CopyAreaMessage *) message; - - *logofs << name() << ": Identity src_drawable " << copyArea -> src_drawable - << ", dst_drawable " << copyArea -> dst_drawable << ", gcontext " << copyArea -> gcontext - << ", src_x " << copyArea -> src_x << ", src_y " << copyArea -> src_y - << ", dst_x " << copyArea -> dst_x << ", dst_y " << copyArea -> dst_y - << ", width " << copyArea -> width << ", height " << copyArea -> height - << ", size " << copyArea -> size_ << ".\n"; - - #endif -} - -void CopyAreaStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 16, 12); -} - -void CopyAreaStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - CopyAreaMessage *copyArea = (CopyAreaMessage *) message; - CopyAreaMessage *cachedCopyArea = (CopyAreaMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << copyArea -> src_drawable - << " as " << "src_drawable" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(copyArea -> src_drawable, clientCache -> drawableCache); - - cachedCopyArea -> src_drawable = copyArea -> src_drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << copyArea -> dst_drawable - << " as " << "dst_drawable" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(copyArea -> dst_drawable, clientCache -> drawableCache); - - cachedCopyArea -> dst_drawable = copyArea -> dst_drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << copyArea -> gcontext - << " as " << "gcontext" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(copyArea -> gcontext, clientCache -> gcCache); - - cachedCopyArea -> gcontext = copyArea -> gcontext; -} - -void CopyAreaStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - CopyAreaMessage *copyArea = (CopyAreaMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - copyArea -> src_drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << copyArea -> src_drawable - << " as " << "src_drawable" << " field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - copyArea -> dst_drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << copyArea -> dst_drawable - << " as " << "dst_drawable" << " field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - copyArea -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << copyArea -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/CopyArea.h b/nxcomp/CopyArea.h deleted file mode 100644 index 6b2617875..000000000 --- a/nxcomp/CopyArea.h +++ /dev/null @@ -1,192 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef CopyArea_H -#define CopyArea_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define COPYAREA_ENABLE_CACHE 1 -#define COPYAREA_ENABLE_DATA 0 -#define COPYAREA_ENABLE_SPLIT 0 -#define COPYAREA_ENABLE_COMPRESS 0 - -#define COPYAREA_DATA_LIMIT 0 -#define COPYAREA_DATA_OFFSET 28 - -#define COPYAREA_CACHE_SLOTS 3000 -#define COPYAREA_CACHE_THRESHOLD 5 -#define COPYAREA_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class CopyAreaMessage : public Message -{ - friend class CopyAreaStore; - - public: - - CopyAreaMessage() - { - } - - ~CopyAreaMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int src_drawable; - unsigned int dst_drawable; - unsigned int gcontext; - unsigned short src_x; - unsigned short src_y; - unsigned short dst_x; - unsigned short dst_y; - unsigned short width; - unsigned short height; -}; - -class CopyAreaStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - CopyAreaStore() : MessageStore() - { - enableCache = COPYAREA_ENABLE_CACHE; - enableData = COPYAREA_ENABLE_DATA; - enableSplit = COPYAREA_ENABLE_SPLIT; - enableCompress = COPYAREA_ENABLE_COMPRESS; - - dataLimit = COPYAREA_DATA_LIMIT; - dataOffset = COPYAREA_DATA_OFFSET; - - cacheSlots = COPYAREA_CACHE_SLOTS; - cacheThreshold = COPYAREA_CACHE_THRESHOLD; - cacheLowerThreshold = COPYAREA_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~CopyAreaStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "CopyArea"; - } - - virtual unsigned char opcode() const - { - return X_CopyArea; - } - - virtual unsigned int storage() const - { - return sizeof(CopyAreaMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new CopyAreaMessage(); - } - - virtual Message *create(const Message &message) const - { - return new CopyAreaMessage((const CopyAreaMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (CopyAreaMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* CopyArea_H */ diff --git a/nxcomp/CreateGC.cpp b/nxcomp/CreateGC.cpp deleted file mode 100644 index 30a2f674e..000000000 --- a/nxcomp/CreateGC.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "CreateGC.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int CreateGCStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - CreateGCMessage *createGC = (CreateGCMessage *) message; - - // - // Here is the fingerprint. - // - - createGC -> gcontext = GetULONG(buffer + 4, bigEndian); - createGC -> drawable = GetULONG(buffer + 8, bigEndian); - createGC -> value_mask = GetULONG(buffer + 12, bigEndian); - - // - // Clear the unused bytes carried in the - // payload to increase the effectiveness - // of the caching algorithm. - // - - if ((int) size > dataOffset) - { - #ifdef DEBUG - *logofs << name() << ": Removing unused bytes from the " - << "data payload.\n" << logofs_flush; - #endif - - createGC -> value_mask &= (1 << 23) - 1; - - unsigned int mask = 0x1; - unsigned char *source = (unsigned char *) buffer + CREATEGC_DATA_OFFSET; - unsigned long value = 0; - - for (unsigned int i = 0; i < 23; i++) - { - if (createGC -> value_mask & mask) - { - value = GetULONG(source, bigEndian); - - value &= (0xffffffff >> (32 - CREATEGC_FIELD_WIDTH[i])); - - PutULONG(value, source, bigEndian); - - source += 4; - } - - mask <<= 1; - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int CreateGCStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - CreateGCMessage *createGC = (CreateGCMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(createGC -> gcontext, buffer + 4, bigEndian); - PutULONG(createGC -> drawable, buffer + 8, bigEndian); - PutULONG(createGC -> value_mask, buffer + 12, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void CreateGCStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - CreateGCMessage *createGC = (CreateGCMessage *) message; - - *logofs << name() << ": Identity gcontext " << createGC -> gcontext << ", drawable " - << createGC -> drawable << ", value_mask " << createGC -> value_mask - << ", size " << createGC -> size_ << ".\n" << logofs_flush; - #endif -} - -void CreateGCStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // This didn't include the drawable - // in previous versions. - // - - md5_append(md5_state_, buffer + 8, 8); -} - -void CreateGCStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - CreateGCMessage *createGC = (CreateGCMessage *) message; - CreateGCMessage *cachedCreateGC = (CreateGCMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - // Since ProtoStep7 (#issue 108) - #ifdef TEST - *logofs << name() << ": Encoding value " << createGC -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeNewXidValue(createGC -> gcontext, clientCache -> lastId, - clientCache -> lastIdCache, clientCache -> gcCache, - clientCache -> freeGCCache); - - cachedCreateGC -> gcontext = createGC -> gcontext; -} - -void CreateGCStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - CreateGCMessage *createGC = (CreateGCMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeNewXidValue(value, clientCache -> lastId, - clientCache -> lastIdCache, clientCache -> gcCache, - clientCache -> freeGCCache); - - createGC -> gcontext = value; - - #ifdef TEST - *logofs << name() << ": Decoded value " << createGC -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} diff --git a/nxcomp/CreateGC.h b/nxcomp/CreateGC.h deleted file mode 100644 index 03e27d685..000000000 --- a/nxcomp/CreateGC.h +++ /dev/null @@ -1,186 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef CreateGC_H -#define CreateGC_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define CREATEGC_ENABLE_CACHE 1 -#define CREATEGC_ENABLE_DATA 0 -#define CREATEGC_ENABLE_SPLIT 0 -#define CREATEGC_ENABLE_COMPRESS 0 - -#define CREATEGC_DATA_LIMIT 144 -#define CREATEGC_DATA_OFFSET 16 - -#define CREATEGC_CACHE_SLOTS 2000 -#define CREATEGC_CACHE_THRESHOLD 2 -#define CREATEGC_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class CreateGCMessage : public Message -{ - friend class CreateGCStore; - - public: - - CreateGCMessage() - { - } - - ~CreateGCMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int gcontext; - unsigned int drawable; - unsigned int value_mask; -}; - -class CreateGCStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - CreateGCStore() : MessageStore() - { - enableCache = CREATEGC_ENABLE_CACHE; - enableData = CREATEGC_ENABLE_DATA; - enableSplit = CREATEGC_ENABLE_SPLIT; - enableCompress = CREATEGC_ENABLE_COMPRESS; - - dataLimit = CREATEGC_DATA_LIMIT; - dataOffset = CREATEGC_DATA_OFFSET; - - cacheSlots = CREATEGC_CACHE_SLOTS; - cacheThreshold = CREATEGC_CACHE_THRESHOLD; - cacheLowerThreshold = CREATEGC_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~CreateGCStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "CreateGC"; - } - - virtual unsigned char opcode() const - { - return X_CreateGC; - } - - virtual unsigned int storage() const - { - return sizeof(CreateGCMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new CreateGCMessage(); - } - - virtual Message *create(const Message &message) const - { - return new CreateGCMessage((const CreateGCMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (CreateGCMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* CreateGC_H */ diff --git a/nxcomp/CreatePixmap.cpp b/nxcomp/CreatePixmap.cpp deleted file mode 100644 index 93ca38fbb..000000000 --- a/nxcomp/CreatePixmap.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "CreatePixmap.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Constructors and destructors. -// - -CreatePixmapStore::CreatePixmapStore() - - : MessageStore() -{ - enableCache = CREATEPIXMAP_ENABLE_CACHE; - enableData = CREATEPIXMAP_ENABLE_DATA; - enableSplit = CREATEPIXMAP_ENABLE_SPLIT; - enableCompress = CREATEPIXMAP_ENABLE_COMPRESS; - - dataLimit = CREATEPIXMAP_DATA_LIMIT; - dataOffset = CREATEPIXMAP_DATA_OFFSET; - - cacheSlots = CREATEPIXMAP_CACHE_SLOTS; - cacheThreshold = CREATEPIXMAP_CACHE_THRESHOLD; - cacheLowerThreshold = CREATEPIXMAP_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -CreatePixmapStore::~CreatePixmapStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int CreatePixmapStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(*(buffer + 1), 8, - clientCache -> depthCache); - - encodeBuffer.encodeNewXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> drawableCache, - clientCache -> freeDrawableCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), - clientCache -> windowCache); - - encodeBuffer.encodeCachedValue(GetUINT(buffer + 12, bigEndian), 16, - clientCache -> createPixmapXCache, 8); - - encodeBuffer.encodeCachedValue(GetUINT(buffer + 14, bigEndian), 16, - clientCache -> createPixmapYCache, 8); - - #ifdef TEST - *logofs << name() << ": Encoded message. Size is " - << size << ".\n" << logofs_flush; - #endif - - return 1; -} - -int CreatePixmapStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned char cValue; - unsigned int value; - - size = 16; - - buffer = writeBuffer -> addMessage(size); - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - - *(buffer + 1) = cValue; - - decodeBuffer.decodeNewXidValue(value, - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> drawableCache, - clientCache -> freeDrawableCache); - - PutULONG(value, buffer + 4, bigEndian); - - decodeBuffer.decodeXidValue(value, - clientCache -> windowCache); - - PutULONG(value, buffer + 8, bigEndian); - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> createPixmapXCache, 8); - - PutUINT(value, buffer + 12, bigEndian); - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> createPixmapYCache, 8); - - PutUINT(value, buffer + 14, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Size is " - << size << ".\n" << logofs_flush; - #endif - - return 1; -} - -int CreatePixmapStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - CreatePixmapMessage *createPixmap = (CreatePixmapMessage *) message; - - createPixmap -> depth = *(buffer + 1); - - createPixmap -> id = GetULONG(buffer + 4, bigEndian); - createPixmap -> drawable = GetULONG(buffer + 8, bigEndian); - - createPixmap -> width = GetUINT(buffer + 12, bigEndian); - createPixmap -> height = GetUINT(buffer + 14, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Size is " - << createPixmap -> size_ << " identity is " - << createPixmap -> i_size_ << ".\n" - << logofs_flush; - #endif - - return 1; -} - -int CreatePixmapStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - CreatePixmapMessage *createPixmap = (CreatePixmapMessage *) message; - - *(buffer + 1) = createPixmap -> depth; - - PutULONG(createPixmap -> id, buffer + 4, bigEndian); - PutULONG(createPixmap -> drawable, buffer + 8, bigEndian); - - PutUINT(createPixmap -> width, buffer + 12, bigEndian); - PutUINT(createPixmap -> height, buffer + 14, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Size is " - << createPixmap -> size_ << " identity is " - << createPixmap -> i_size_ << ".\n" - << logofs_flush; - #endif - - return 1; -} - -void CreatePixmapStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - #ifdef WARNING - *logofs << name() << ": WARNING! Dump of identity not implemented.\n" - << logofs_flush; - #endif - - #endif -} - -void CreatePixmapStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 1, 1); - md5_append(md5_state_, buffer + 8, 8); -} - -void CreatePixmapStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - CreatePixmapMessage *createPixmap = (CreatePixmapMessage *) message; - CreatePixmapMessage *cachedCreatePixmap = (CreatePixmapMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeNewXidValue(createPixmap -> id, - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> drawableCache, - clientCache -> freeDrawableCache); - - cachedCreatePixmap -> id = createPixmap -> id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Size is " - << createPixmap -> size_ << " identity is " - << createPixmap -> i_size_ << ".\n" - << logofs_flush; - #endif -} - -void CreatePixmapStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - CreatePixmapMessage *createPixmap = (CreatePixmapMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeNewXidValue(createPixmap -> id, - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> drawableCache, - clientCache -> freeDrawableCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Size is " - << createPixmap -> size_ << " identity is " - << createPixmap -> i_size_ << ".\n" - << logofs_flush; - #endif -} diff --git a/nxcomp/CreatePixmap.h b/nxcomp/CreatePixmap.h deleted file mode 100644 index 0a3212dd9..000000000 --- a/nxcomp/CreatePixmap.h +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef CreatePixmap_H -#define CreatePixmap_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define CREATEPIXMAP_ENABLE_CACHE 1 -#define CREATEPIXMAP_ENABLE_DATA 0 -#define CREATEPIXMAP_ENABLE_SPLIT 0 -#define CREATEPIXMAP_ENABLE_COMPRESS 0 - -#define CREATEPIXMAP_DATA_LIMIT 16 -#define CREATEPIXMAP_DATA_OFFSET 16 - -#define CREATEPIXMAP_CACHE_SLOTS 1000 -#define CREATEPIXMAP_CACHE_THRESHOLD 2 -#define CREATEPIXMAP_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class CreatePixmapMessage : public Message -{ - friend class CreatePixmapStore; - - public: - - CreatePixmapMessage() - { - } - - ~CreatePixmapMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char depth; - - unsigned int id; - unsigned int drawable; - - unsigned short width; - unsigned short height; -}; - -class CreatePixmapStore : public MessageStore -{ - public: - - CreatePixmapStore(); - - virtual ~CreatePixmapStore(); - - virtual const char *name() const - { - return "CreatePixmap"; - } - - virtual unsigned char opcode() const - { - return X_CreatePixmap; - } - - virtual unsigned int storage() const - { - return sizeof(CreatePixmapMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new CreatePixmapMessage(); - } - - virtual Message *create(const Message &message) const - { - return new CreatePixmapMessage((const CreatePixmapMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (CreatePixmapMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* CreatePixmap_H */ diff --git a/nxcomp/DecodeBuffer.cpp b/nxcomp/DecodeBuffer.cpp deleted file mode 100644 index 456dee249..000000000 --- a/nxcomp/DecodeBuffer.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "Control.h" - -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -DecodeBuffer::DecodeBuffer(const unsigned char *data, unsigned int length) - - : buffer_(data), end_(buffer_ + length), nextSrc_(buffer_), srcMask_(0x80) -{ - // Since ProtoStep7 (#issue 108) - end_ = buffer_ + length - DECODE_BUFFER_POSTFIX_SIZE; -} - -int DecodeBuffer::decodeValue(unsigned int &value, unsigned int numBits, - unsigned int blockSize, int endOkay) -{ - #ifdef DUMP - *logofs << "DecodeBuffer: Decoding " << numBits - << " bits value with block " << blockSize - << " and " << (nextSrc_ - buffer_) - << " bytes in buffer.\n" << logofs_flush; - #endif - - unsigned int result = 0; - unsigned int destMask = 0x1; - unsigned int bitsRead = 0; - - if (blockSize == 0) - blockSize = numBits; - - unsigned char nextSrcChar = *nextSrc_; - unsigned int numBlocks = 1; - - do - { - if (numBlocks == 4) - { - blockSize = numBits; - } - - unsigned int bitsToRead = (blockSize > numBits - bitsRead ? - numBits - bitsRead : blockSize); - unsigned int count = 0; - unsigned char lastBit; - - do - { - if (nextSrc_ >= end_) - { - if (!endOkay) - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [A] " - << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) - << " end_ = " << (end_ - buffer_) << ".\n" - << logofs_flush; - #endif - - // - // Label "context" is just used to identify - // the routine which detected the problem in - // present source file. - // - - cerr << "Error" << ": Failure decoding data in context [A].\n"; - - HandleAbort(); - } - - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [B] " - << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) - << " end_ = " << (end_ - buffer_) << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [B].\n"; - - HandleAbort(); - } - - lastBit = (nextSrcChar & srcMask_); - - if (lastBit) - result |= destMask; - - srcMask_ >>= 1; - - if (srcMask_ == 0) - { - srcMask_ = 0x80; - nextSrc_++; - nextSrcChar = *nextSrc_; - } - - destMask <<= 1; - } - while (bitsToRead > ++count); - - bitsRead += bitsToRead; - - if (bitsRead < numBits) - { - if (nextSrc_ >= end_) - { - if (!endOkay) - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [C] " - << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) - << " end_ = " << (end_ - buffer_) << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [C].\n"; - - HandleAbort(); - } - - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [D] " - << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) - << " end_ = " << (end_ - buffer_) << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [D].\n"; - - HandleAbort(); - } - - unsigned char moreData = (nextSrcChar & srcMask_); - - srcMask_ >>= 1; - - if (srcMask_ == 0) - { - srcMask_ = 0x80; - nextSrc_++; - nextSrcChar = *nextSrc_; - } - - if (!moreData) - { - if (lastBit) - { - do - { - result |= destMask; - destMask <<= 1; - } - while (numBits > ++bitsRead); - } - else - bitsRead = numBits; - } - } - - blockSize >>= 1; - - if (blockSize < 2) - blockSize = 2; - - numBlocks++; - } - while (numBits > bitsRead); - - value = result; - - return 1; -} - -int DecodeBuffer::decodeCachedValue(unsigned int &value, unsigned int numBits, - IntCache &cache, unsigned int blockSize, - int endOkay) -{ - #ifdef DUMP - *logofs << "DecodeBuffer: Decoding " << numBits - << " bits cached value with block " << blockSize - << " and " << (nextSrc_ - buffer_) - << " bytes in buffer.\n" << logofs_flush; - #endif - - if (nextSrc_ >= end_) - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [E] " - << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) - << " end_ = " << (end_ - buffer_) << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [E].\n"; - - HandleAbort(); - } - - unsigned int index = 0; - unsigned char nextSrcChar = *nextSrc_; - - while (!(nextSrcChar & srcMask_)) - { - index++; - srcMask_ >>= 1; - if (srcMask_ == 0) - { - srcMask_ = 0x80; - nextSrc_++; - if (nextSrc_ >= end_) - { - if (!endOkay) - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [F] " - << "in decodeCachedValue() nextSrc_ = " - << (nextSrc_ - buffer_) << " end_ = " - << (end_ - buffer_) << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [F].\n"; - - HandleAbort(); - } - - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [G] " - << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) - << " end_ = " << (end_ - buffer_) << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [G].\n"; - - HandleAbort(); - } - - nextSrcChar = *nextSrc_; - } - } - - srcMask_ >>= 1; - - if (srcMask_ == 0) - { - srcMask_ = 0x80; - nextSrc_++; - } - - if (index == 2) - { - // Since ProtoStep8 (#issue 108) - blockSize = cache.getBlockSize(blockSize); - - if (decodeValue(value, numBits, blockSize, endOkay)) - { - cache.insert(value, IntMask[numBits]); - - return 1; - } - - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [H] " - << "in decodeCacheValue() with no value found.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [H].\n"; - - HandleAbort(); - } - else - { - if (index > 2) - { - index--; - } - - if (index > cache.getSize()) - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [I] " - << "in decodeCachedValue() index = " << index - << " cache size = " << cache.getSize() << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [I].\n"; - - HandleAbort(); - } - - value = cache.get(index); - - return 1; - } -} - -int DecodeBuffer::decodeCachedValue(unsigned char &value, unsigned int numBits, - CharCache &cache, unsigned int blockSize, - int endOkay) -{ - #ifdef DUMP - *logofs << "DecodeBuffer: Decoding " << numBits - << " bits char cached value with block " << blockSize - << " and " << nextSrc_ - buffer_ << " bytes read out of " - << end_ - buffer_ << ".\n" << logofs_flush; - #endif - - if (nextSrc_ >= end_) - { - #ifdef TEST - *logofs << "DecodeBuffer: End of buffer reached in context [J] with " - << nextSrc_ - buffer_ << " bytes read out of " - << end_ - buffer_ << ".\n" << logofs_flush; - #endif - - return 0; - } - - unsigned int index = 0; - unsigned char nextSrcChar = *nextSrc_; - - while (!(nextSrcChar & srcMask_)) - { - index++; - srcMask_ >>= 1; - - if (srcMask_ == 0) - { - srcMask_ = 0x80; - nextSrc_++; - - if (nextSrc_ >= end_) - { - if (!endOkay) - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [K] " - << "in decodeCachedValue() nextSrc_ " - << (nextSrc_ - buffer_) << " end_ " << (end_ - buffer_) - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [K].\n"; - - HandleAbort(); - } - - #ifdef TEST - *logofs << "DecodeBuffer: End of buffer reached in context [L] with " - << nextSrc_ - buffer_ << " bytes read out of " - << end_ - buffer_ << ".\n" << logofs_flush; - #endif - - return 0; - } - - nextSrcChar = *nextSrc_; - } - } - - srcMask_ >>= 1; - - if (srcMask_ == 0) - { - srcMask_ = 0x80; - nextSrc_++; - } - - if (index == 2) - { - unsigned int temp; - - if (decodeValue(temp, numBits, blockSize, endOkay)) - { - value = (unsigned char) temp; - - cache.insert(value); - } - else - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [M] " - << "in decodeValue() with index = 2.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [M].\n"; - - HandleAbort(); - } - } - else - { - if (index > 2) - { - index--; - } - - if (index > cache.getSize()) - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [N] " - << "in decodeCachedValue() " << "index = " << index - << " cache size = " << cache.getSize() << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [N].\n"; - - HandleAbort(); - } - - value = cache.get(index); - } - - return 1; -} - -// -// Simply returns a pointer to the correct spot in -// the internal buffer. If the caller needs this -// data to last beyond the lifetime of the internal -// buffer, it must copy the data in its own memory. -// - -const unsigned char *DecodeBuffer::decodeMemory(unsigned int numBytes) -{ - #ifdef DUMP - *logofs << "DecodeBuffer: Decoding " << numBytes - << " bytes of memory with " << (nextSrc_ - buffer_) - << " bytes in buffer.\n" << logofs_flush; - #endif - - const unsigned char *result; - - // - // Force ourselves to a byte boundary. - // Is up to application to ensure data - // is word alligned when needed. - // - - if (srcMask_ != 0x80) - { - srcMask_ = 0x80; - nextSrc_++; - } - - result = nextSrc_; - - if (numBytes > DECODE_BUFFER_OVERFLOW_SIZE) - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Can't decode a buffer of " - << numBytes << " bytes with limit set to " - << DECODE_BUFFER_OVERFLOW_SIZE << ".\n" - << logofs_flush; - - *logofs << "DecodeBuffer: PANIC! Assuming failure decoding " - << "data in context [O].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Should never decode buffer of size " - << "greater than " << DECODE_BUFFER_OVERFLOW_SIZE - << " bytes.\n"; - - cerr << "Error" << ": Assuming failure decoding data in " - << "context [O].\n"; - - HandleAbort(); - } - else if (end_ - nextSrc_ < (int) numBytes) - { - #ifdef PANIC - *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [P] " - << "in decodeMemory() " << "with length " << numBytes - << " and " << (end_ - nextSrc_) - << " bytes remaining.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failure decoding data in context [P].\n"; - - HandleAbort(); - } - - nextSrc_ += numBytes; - - return result; -} - -void DecodeBuffer::decodeActionValue(unsigned char &value, unsigned short &position, - ActionCache &cache) -{ - unsigned int t; - - decodeCachedValue(t, 15, *(cache.base_[cache.slot_])); - - cache.last_ += t; - cache.last_ &= 0x7fff; - - value = cache.last_ >> 13; - - position = cache.last_ & 0x1fff; - - #ifdef DEBUG - *logofs << "DecodeBuffer: Decoded value " - << (unsigned) value << " and position " - << position << " with base " << cache.slot_ - << ".\n" << logofs_flush; - #endif - - #ifdef DEBUG - *logofs << "DecodeBuffer: Action block prediction is " - << (*(cache.base_[cache.slot_])).getBlockSize(15) - << ".\n" << logofs_flush; - #endif - - cache.slot_ = (cache.last_ & 0xff); -} - -void DecodeBuffer::decodeNewXidValue(unsigned int &value, unsigned int &lastId, - IntCache &lastIdCache, IntCache &cache, - FreeCache &freeCache) -{ - decodeCachedValue(value, 29, lastIdCache); - - lastId += (value + 1); - lastId &= 0x1fffffff; - - value = lastId; - - cache.push(value, 0x1fffffff); - - freeCache.push(value, 0x1fffffff); -} - -void DecodeBuffer::decodeNewXidValue(unsigned int &value, unsigned int &lastId, - IntCache &lastIdCache, XidCache &cache, - FreeCache &freeCache) -{ - decodeCachedValue(value, 29, lastIdCache); - - #ifdef DEBUG - *logofs << "DecodeBuffer: Decoded new Xid difference " - << value << ".\n" << logofs_flush; - #endif - - lastId += (value + 1); - lastId &= 0x1fffffff; - - value = lastId; - - unsigned int t = (value - cache.last_); - - cache.last_ = value; - - #ifdef DEBUG - *logofs << "DecodeBuffer: Decoded new Xid " << value - << " with base " << cache.slot_ << ".\n" - << logofs_flush; - #endif - - cache.slot_ = (value & 0xff); - - cache.base_[cache.slot_] -> push(t, 0x1fffffff); - - freeCache.push(value, 0x1fffffff); -} - -void DecodeBuffer::decodeXidValue(unsigned int &value, XidCache &cache) -{ - unsigned int t; - - decodeCachedValue(t, 29, *(cache.base_[cache.slot_])); - - cache.last_ += t; - cache.last_ &= 0x1fffffff; - - value = cache.last_; - - #ifdef DEBUG - *logofs << "DecodeBuffer: Decoded Xid " << value - << " with base " << cache.slot_ << ".\n" - << logofs_flush; - #endif - - cache.slot_ = (value & 0xff); - - #ifdef DEBUG - *logofs << "DecodeBuffer: Xid block prediction is " - << (*(cache.base_[cache.slot_])).getBlockSize(29) - << ".\n" << logofs_flush; - #endif -} - -void DecodeBuffer::decodeFreeXidValue(unsigned int &value, FreeCache &cache) -{ - decodeCachedValue(value, 29, cache); -} - diff --git a/nxcomp/DecodeBuffer.h b/nxcomp/DecodeBuffer.h deleted file mode 100644 index f5f84c54f..000000000 --- a/nxcomp/DecodeBuffer.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef DecodeBuffer_H -#define DecodeBuffer_H - -#include - -#include "IntCache.h" -#include "CharCache.h" -#include "XidCache.h" -#include "FreeCache.h" -#include "OpcodeCache.h" -#include "ActionCache.h" - -#define DECODE_BUFFER_OVERFLOW_SIZE 4194304 - -#define DECODE_BUFFER_POSTFIX_SIZE 1 - -class DecodeBuffer -{ - public: - - DecodeBuffer(const unsigned char *data, unsigned int length); - - ~DecodeBuffer() - { - } - - int decodeValue(unsigned int &value, unsigned int numBits, - unsigned int blockSize = 0, int endOkay = 0); - - int decodeCachedValue(unsigned int &value, unsigned int numBits, - IntCache &cache, unsigned int blockSize = 0, - int endOkay = 0); - - int decodeCachedValue(unsigned char &value, unsigned int numBits, - CharCache &cache, unsigned int blockSize = 0, - int endOkay = 0); - - void decodeDiffCachedValue(unsigned int &value, unsigned int &previous, - unsigned int numBits, IntCache &cache, - unsigned int blockSize = 0) - { - decodeCachedValue(value, numBits, cache, blockSize); - - previous += (value + 1); - previous &= (0xffffffff >> (32 - numBits)); - - value = previous; - } - - void decodeBoolValue(unsigned int &value) - { - decodeValue(value, 1); - } - - int decodeOpcodeValue(unsigned char &value, OpcodeCache &cache, int endOkay = 0) - { - int result = decodeCachedValue(value, 8, cache.base_[cache.slot_], 8, endOkay); - - if (result == 1) - { - cache.slot_ = value; - } - - return result; - } - - void decodeActionValue(unsigned char &value, unsigned short &position, - ActionCache &cache); - - void decodeNewXidValue(unsigned int &value, unsigned int &lastId, - IntCache &lastIdCache, IntCache &cache, - FreeCache &freeCache); - - void decodeNewXidValue(unsigned int &value, unsigned int &lastId, - IntCache &lastIdCache, XidCache &cache, - FreeCache &freeCache); - - void decodeXidValue(unsigned int &value, XidCache &cache); - - void decodeFreeXidValue(unsigned int &value, FreeCache &cache); - - void decodeTextData(unsigned char *buffer, unsigned int numBytes) - { - decodeMemory(buffer, numBytes); - } - - void decodeIntData(unsigned char *buffer, unsigned int numBytes) - { - decodeMemory(buffer, numBytes); - } - - void decodeLongData(unsigned char *buffer, unsigned int numBytes) - { - decodeMemory(buffer, numBytes); - } - - const unsigned char *decodeMemory(unsigned int numBytes); - - void decodeMemory(unsigned char *buffer, unsigned int numBytes) - { - memcpy(buffer, decodeMemory(numBytes), numBytes); - } - - private: - - const unsigned char *buffer_; - const unsigned char *end_; - const unsigned char *nextSrc_; - - unsigned char srcMask_; -}; - -#endif /* DecodeBuffer_H */ diff --git a/nxcomp/EncodeBuffer.cpp b/nxcomp/EncodeBuffer.cpp deleted file mode 100644 index a259aacb2..000000000 --- a/nxcomp/EncodeBuffer.cpp +++ /dev/null @@ -1,619 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "Control.h" - -#include "EncodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -#define ADVANCE_DEST \ -\ -if (destShift_ == 0) \ -{ \ - destShift_ = 7; nextDest_++; *nextDest_ = 0; \ -} \ -else \ -{ \ - destShift_--; \ -} - -EncodeBuffer::EncodeBuffer() -{ - size_ = ENCODE_BUFFER_DEFAULT_SIZE; - - buffer_ = new unsigned char[size_ + ENCODE_BUFFER_PREFIX_SIZE + - ENCODE_BUFFER_POSTFIX_SIZE] + ENCODE_BUFFER_PREFIX_SIZE; - end_ = buffer_ + size_; - - nextDest_ = buffer_; - *nextDest_ = 0; - destShift_ = 7; - - lastBits_ = 0; - - initialSize_ = ENCODE_BUFFER_DEFAULT_SIZE; - thresholdSize_ = ENCODE_BUFFER_DEFAULT_SIZE << 1; - maximumSize_ = ENCODE_BUFFER_DEFAULT_SIZE << 4; -} - -EncodeBuffer::~EncodeBuffer() -{ - delete [] (buffer_ - ENCODE_BUFFER_PREFIX_SIZE); -} - -void EncodeBuffer::setSize(unsigned int initialSize, unsigned int thresholdSize, - unsigned int maximumSize) -{ - initialSize_ = initialSize; - thresholdSize_ = thresholdSize; - maximumSize_ = maximumSize; - - #ifdef TEST - *logofs << "EncodeBuffer: Set buffer sizes to " - << initialSize_ << "/" << thresholdSize_ - << "/" << maximumSize_ << ".\n" - << logofs_flush; - #endif -} - -void EncodeBuffer::fullReset() -{ - if (size_ > initialSize_) - { - delete [] (buffer_ - ENCODE_BUFFER_PREFIX_SIZE); - - size_ = initialSize_; - - buffer_ = new unsigned char[size_ + ENCODE_BUFFER_PREFIX_SIZE + - ENCODE_BUFFER_POSTFIX_SIZE] + ENCODE_BUFFER_PREFIX_SIZE; - } - - end_ = buffer_ + size_; - - nextDest_ = buffer_; - *nextDest_ = 0; - destShift_ = 7; - - lastBits_ = 0; -} - -void EncodeBuffer::encodeValue(unsigned int value, unsigned int numBits, - unsigned int blockSize) -{ - #ifdef DUMP - *logofs << "EncodeBuffer: Encoding " << numBits - << " bits value with block " << blockSize - << " and " << (nextDest_ - buffer_) - << " bytes in buffer.\n" << logofs_flush; - #endif - - value &= IntMask[numBits]; - - unsigned int srcMask = 0x1; - unsigned int bitsWritten = 0; - - if (blockSize == 0) - blockSize = numBits; - - if (end_ - nextDest_ < 8) - { - growBuffer(); - } - - unsigned int numBlocks = 1; - - do - { - if (numBlocks == 4) - blockSize = numBits; - - unsigned int bitsToWrite = (blockSize > numBits - bitsWritten ? - numBits - bitsWritten : blockSize); - unsigned int count = 0; - unsigned int lastBit; - - do - { - lastBit = (value & srcMask); - if (lastBit) - *nextDest_ |= (1 << destShift_); - ADVANCE_DEST; - srcMask <<= 1; - } - while (bitsToWrite > ++count); - - bitsWritten += bitsToWrite; - - if (bitsWritten < numBits) - { - unsigned int tmpMask = srcMask; - unsigned int i = bitsWritten; - - if (lastBit) - { - do - { - unsigned int nextBit = (value & tmpMask); - - if (!nextBit) - break; - - tmpMask <<= 1; - } - while (numBits > ++i); - } - else - { - do - { - unsigned int nextBit = (value & tmpMask); - - if (nextBit) - break; - - tmpMask <<= 1; - } - while (numBits > ++i); - } - - if (i < numBits) - *nextDest_ |= (1 << destShift_); - else - bitsWritten = numBits; - - ADVANCE_DEST; - } - blockSize >>= 1; - - if (blockSize < 2) - blockSize = 2; - - numBlocks++; - } - while (numBits > bitsWritten); -} - -void EncodeBuffer::encodeCachedValue(unsigned int value, unsigned int numBits, - IntCache &cache, unsigned int blockSize) -{ - #ifdef DUMP - *logofs << "EncodeBuffer: Encoding " << numBits - << " bits cached value with block " << blockSize - << " and " << (nextDest_ - buffer_) - << " bytes in buffer.\n" << logofs_flush; - #endif - - value &= IntMask[numBits]; - - if (end_ - nextDest_ < 8) - { - growBuffer(); - } - - blockSize = cache.getBlockSize(blockSize); - - unsigned int index; - unsigned int sameDiff; - - #ifdef DUMP - - diffBits(); - - #endif - - if (cache.lookup(value, index, IntMask[numBits], sameDiff)) - { - if (index > 1) - index++; - - while (destShift_ < index) - { - index -= destShift_; - index--; - destShift_ = 7; - nextDest_++; - *nextDest_ = 0; - } - - destShift_ -= index; - *nextDest_ |= (1 << destShift_); - ADVANCE_DEST; - - #ifdef DUMP - *logofs << "EncodeBuffer: Encoded cached int using " - << diffBits() << " bits out of " << numBits - << ".\n" << logofs_flush; - #endif - } - else - { - ADVANCE_DEST; - ADVANCE_DEST; - *nextDest_ |= (1 << destShift_); - ADVANCE_DEST; - - // - // The attempt is very seldom successful. - // Avoid to encode the additional bool. - // - - // Since ProtoStep8 (#issue 108) - #ifdef DUMP - *logofs << "EncodeBuffer: Encoded missed int using " - << diffBits() << " bits out of " << numBits - << ".\n" << logofs_flush; - #endif - - encodeValue(value, numBits, blockSize); - } -} - -void EncodeBuffer::encodeCachedValue(unsigned char value, unsigned int numBits, - CharCache &cache, unsigned int blockSize) -{ - #ifdef DUMP - *logofs << "EncodeBuffer: Encoding " << numBits - << " bits char cached value with block " << blockSize - << " and " << (nextDest_ - buffer_) - << " bytes in buffer.\n" << logofs_flush; - #endif - - value &= IntMask[numBits]; - - if (end_ - nextDest_ < 8) - { - growBuffer(); - } - - unsigned int index; - - #ifdef DUMP - - diffBits(); - - #endif - - if (cache.lookup(value, index)) - { - if (index > 1) - index++; - - while (destShift_ < index) - { - index -= destShift_; - index--; - destShift_ = 7; - nextDest_++; - *nextDest_ = 0; - } - - destShift_ -= index; - *nextDest_ |= (1 << destShift_); - ADVANCE_DEST; - - #ifdef DUMP - *logofs << "EncodeBuffer: Encoded cached char using " - << diffBits() << " bits out of " << numBits - << ".\n" << logofs_flush; - #endif - } - else - { - ADVANCE_DEST; - ADVANCE_DEST; - *nextDest_ |= (1 << destShift_); - ADVANCE_DEST; - - encodeValue(value, numBits, blockSize); - - #ifdef DUMP - *logofs << "EncodeBuffer: Encoded missed char using " - << diffBits() << " bits out of " << numBits - << ".\n" << logofs_flush; - #endif - } -} - -void EncodeBuffer::encodeMemory(const unsigned char *buffer, unsigned int numBytes) -{ - #ifdef DUMP - *logofs << "EncodeBuffer: Encoding " << numBytes - << " bytes of memory with " << (nextDest_ - buffer_) - << " bytes in buffer.\n" << logofs_flush; - #endif - - if (numBytes > ENCODE_BUFFER_OVERFLOW_SIZE) - { - #ifdef PANIC - *logofs << "EncodeBuffer: PANIC! Should never encode buffer " - << "of size greater than " << ENCODE_BUFFER_OVERFLOW_SIZE - << " bytes.\n" << logofs_flush; - - *logofs << "EncodeBuffer: PANIC! Assuming failure encoding data " - << "in context [A].\n" << logofs_flush; - #endif - - // - // Label "context" is just used to identify - // the routine which detected the problem in - // present source file. - // - - cerr << "Error" << ": Should never encode buffer of size " - << "greater than " << ENCODE_BUFFER_OVERFLOW_SIZE - << " bytes.\n"; - - cerr << "Error" << ": Assuming failure encoding data " - << "in context [A].\n" ; - - HandleAbort(); - } - - alignBuffer(); - - if (end_ - nextDest_ < (int) numBytes) - { - growBuffer(numBytes); - } - - memcpy(nextDest_, buffer, numBytes); - - nextDest_ += numBytes; - - if (nextDest_ == end_) - { - growBuffer(); - } - else if (nextDest_ > end_) - { - #ifdef PANIC - *logofs << "EncodeBuffer: PANIC! Assertion failed. Error [B] " - << "in encodeMemory() nextDest_ " << (nextDest_ - buffer) - << " end_ " << (end_ - buffer) << ".\n" - << logofs_flush; - #endif - - // - // Label "context" is just used to identify - // the routine which detected the problem in - // present source file. - // - - cerr << "Error" << ": Failure encoding raw data " - << "in context [B].\n" ; - - HandleAbort(); - } - - *nextDest_ = 0; -} - -unsigned int EncodeBuffer::getLength() const -{ - unsigned int length = nextDest_ - buffer_; - - if (destShift_ != 7) - { - length++; - } - - // Since ProtoStep7 (#issue 108) - if (length > 0) - { - return length + ENCODE_BUFFER_POSTFIX_SIZE; - } - - return length; -} - -unsigned int EncodeBuffer::diffBits() -{ - unsigned int bits = ((nextDest_ - buffer_) << 3); - - bits += (7 - destShift_); - - unsigned int diff = bits - lastBits_; - - lastBits_ = bits; - - return diff; -} - -void EncodeBuffer::growBuffer(unsigned int numBytes) -{ - if (numBytes == 0) - { - numBytes = initialSize_; - } - - unsigned int bytesInBuffer = nextDest_ - buffer_; - - unsigned int newSize = thresholdSize_; - - while (newSize < bytesInBuffer + numBytes) - { - newSize <<= 1; - - if (newSize > maximumSize_) - { - newSize = bytesInBuffer + numBytes + initialSize_; - } - } - - unsigned char *newBuffer; - - newBuffer = new unsigned char[newSize + ENCODE_BUFFER_PREFIX_SIZE + - ENCODE_BUFFER_POSTFIX_SIZE] + ENCODE_BUFFER_PREFIX_SIZE; - - if (newBuffer == NULL) - { - #ifdef PANIC - *logofs << "EncodeBuffer: PANIC! Error in context [C] " - << "growing buffer to accommodate " << numBytes - << " bytes .\n" << logofs_flush; - #endif - - cerr << "Error" << ": Error in context [C] " - << "growing encode buffer to accommodate " - << numBytes << " bytes.\n"; - - HandleAbort(); - } - - #ifdef TEST - if (newSize >= maximumSize_) - { - *logofs << "EncodeBuffer: WARNING! Buffer grown to reach " - << "size of " << newSize << " bytes.\n" - << logofs_flush; - } - #endif - - // - // Prefix should not contain any valid data. - // It is proxy that will fill it with control - // messages and data length at the time a new - // frame is written to socket. - // - - memcpy(newBuffer, buffer_, bytesInBuffer + 1); - - newBuffer[bytesInBuffer + 1] = 0; - - delete [] (buffer_ - ENCODE_BUFFER_PREFIX_SIZE); - - buffer_ = newBuffer; - size_ = newSize; - end_ = buffer_ + size_; - - nextDest_ = buffer_ + bytesInBuffer; -} - -void EncodeBuffer::alignBuffer() -{ - if (destShift_ != 7) - { - destShift_ = 7; - nextDest_++; - - if (nextDest_ >= end_) - { - growBuffer(); - } - - *nextDest_ = 0; - } -} - -void EncodeBuffer::encodeActionValue(unsigned char value, unsigned short position, - ActionCache &cache) -{ - unsigned int v = (value << 13) | position; - - unsigned int t = (v - cache.last_); - - encodeCachedValue(t, 15, *(cache.base_[cache.slot_])); - - cache.last_ = v; - - #ifdef DEBUG - *logofs << "EncodeBuffer: Encoded value " - << (unsigned) value << " and position " - << position << " with base " << cache.slot_ - << ".\n" << logofs_flush; - #endif - - cache.slot_ = (cache.last_ & 0xff); -} - -void EncodeBuffer::encodeNewXidValue(unsigned int value, unsigned int &lastId, - IntCache &lastIdCache, IntCache &cache, - FreeCache &freeCache) -{ - encodeCachedValue((value - 1) - lastId, 29, lastIdCache); - - lastId = value; - - cache.push(value, 0x1fffffff); - - freeCache.push(value, 0x1fffffff); -} - -void EncodeBuffer::encodeNewXidValue(unsigned int value, unsigned int &lastId, - IntCache &lastIdCache, XidCache &cache, - FreeCache &freeCache) -{ - encodeCachedValue((value - 1) - lastId, 29, lastIdCache); - - lastId = value; - - unsigned int t = (value - cache.last_); - - cache.last_ = value; - - #ifdef DEBUG - *logofs << "EncodeBuffer: Encoded new Xid " << value - << " with base " << cache.slot_ << ".\n" - << logofs_flush; - #endif - - cache.slot_ = (value & 0xff); - - cache.base_[cache.slot_] -> push(t, 0x1fffffff); - - freeCache.push(value, IntMask[29]); -} - -void EncodeBuffer::encodeXidValue(unsigned int value, XidCache &cache) -{ - unsigned int t = (value - cache.last_); - - encodeCachedValue(t, 29, *(cache.base_[cache.slot_])); - - cache.last_ = value; - - #ifdef DEBUG - *logofs << "EncodeBuffer: Encoded Xid " << value - << " with base " << cache.slot_ << ".\n" - << logofs_flush; - #endif - - cache.slot_ = (value & 0xff); -} - -void EncodeBuffer::encodeFreeXidValue(unsigned int value, FreeCache &cache) -{ - encodeCachedValue(value, 29, cache); -} diff --git a/nxcomp/EncodeBuffer.h b/nxcomp/EncodeBuffer.h deleted file mode 100644 index 67f6ff093..000000000 --- a/nxcomp/EncodeBuffer.h +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef EncodeBuffer_H -#define EncodeBuffer_H - -#include "IntCache.h" -#include "CharCache.h" -#include "XidCache.h" -#include "FreeCache.h" -#include "OpcodeCache.h" -#include "ActionCache.h" - -#define ENCODE_BUFFER_DEFAULT_SIZE 16384 - -// -// This should match the maximum size of -// a single message added to write buffer -// (see WriteBuffer.h). -// - -#define ENCODE_BUFFER_OVERFLOW_SIZE 4194304 - -// -// Adjust for the control messages and the -// frame length added by the proxy. -// - -#define ENCODE_BUFFER_PREFIX_SIZE 64 - -// -// The encode routines may write one byte -// past the nominal end of the encode buffer. -// This additional byte is included in the -// payload. This is actually a harmless bug. -// - -#define ENCODE_BUFFER_POSTFIX_SIZE 1 - -class EncodeBuffer -{ - public: - - EncodeBuffer(); - - ~EncodeBuffer(); - - void setSize(unsigned int initialSize, unsigned int thresholdSize, - unsigned int maximumSize); - - void encodeValue(unsigned int value, unsigned int numBits, - unsigned int blockSize = 0); - - void encodeCachedValue(unsigned int value, unsigned int numBits, - IntCache &cache, unsigned int blockSize = 0); - - void encodeCachedValue(unsigned char value, unsigned int numBits, - CharCache &cache, unsigned int blockSize = 0); - - void encodeDiffCachedValue(const unsigned int value, unsigned int &previous, - unsigned int numBits, IntCache &cache, - unsigned int blockSize = 0) - { - encodeCachedValue((value - 1) - previous, numBits, cache, blockSize); - - previous = value; - } - - void encodeBoolValue(unsigned int value) - { - encodeValue(value, 1); - } - - void encodeOpcodeValue(unsigned char value, OpcodeCache &cache) - { - encodeCachedValue(value, 8, cache.base_[cache.slot_], 8); - - cache.slot_ = value; - } - - void encodeActionValue(unsigned char value, ActionCache &cache) - { - unsigned short position = 0; - - encodeActionValue(value, position, cache); - } - - void encodeActionValue(unsigned char value, unsigned short position, - ActionCache &cache); - - void encodeNewXidValue(unsigned int value, unsigned int &lastId, - IntCache &lastIdCache, IntCache &cache, - FreeCache &freeCache); - - void encodeNewXidValue(unsigned int value, unsigned int &lastId, - IntCache &lastIdCache, XidCache &cache, - FreeCache &freeCache); - - void encodeXidValue(unsigned int value, XidCache &cache); - - void encodeFreeXidValue(unsigned int value, FreeCache &cache); - - void encodeTextData(const unsigned char *buffer, unsigned int numBytes) - { - encodeMemory(buffer, numBytes); - } - - void encodeIntData(const unsigned char *buffer, unsigned int numBytes) - { - encodeMemory(buffer, numBytes); - } - - void encodeLongData(const unsigned char *buffer, unsigned int numBytes) - { - encodeMemory(buffer, numBytes); - } - - void encodeMemory(const unsigned char *buffer, unsigned int numBytes); - - unsigned char *getData() - { - return buffer_; - } - - unsigned int getLength() const; - - unsigned int getBits() const - { - return ((nextDest_ - buffer_) << 3) + (7 - destShift_); - } - - unsigned int diffBits(); - - void fullReset(); - - private: - - void growBuffer(unsigned int numBytes = 0); - - void alignBuffer(); - - unsigned int size_; - unsigned char *buffer_; - - // - // This points to the first byte - // just beyond end of the buffer. - // - - const unsigned char *end_; - - unsigned char *nextDest_; - unsigned int destShift_; - unsigned int lastBits_; - - unsigned int initialSize_; - unsigned int thresholdSize_; - unsigned int maximumSize_; -}; - -#endif /* EncodeBuffer_H */ diff --git a/nxcomp/FillPoly.cpp b/nxcomp/FillPoly.cpp deleted file mode 100644 index 85fa8fdd1..000000000 --- a/nxcomp/FillPoly.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "FillPoly.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int FillPolyStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - FillPolyMessage *fillPoly = (FillPolyMessage *) message; - - // - // Here is the fingerprint. - // - - fillPoly -> drawable = GetULONG(buffer + 4, bigEndian); - fillPoly -> gcontext = GetULONG(buffer + 8, bigEndian); - - fillPoly -> shape = *(buffer + 12); - fillPoly -> mode = *(buffer + 13); - - // Since ProtoStep8 (#issue 108) - if (size >= (unsigned int) dataOffset) - { - fillPoly -> x_origin = GetUINT(buffer + 16, bigEndian); - fillPoly -> y_origin = GetUINT(buffer + 18, bigEndian); - } - else - { - fillPoly -> x_origin = 0; - fillPoly -> y_origin = 0; - } - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int FillPolyStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - FillPolyMessage *fillPoly = (FillPolyMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(fillPoly -> drawable, buffer + 4, bigEndian); - PutULONG(fillPoly -> gcontext, buffer + 8, bigEndian); - - *(buffer + 12) = fillPoly -> shape; - *(buffer + 13) = fillPoly -> mode; - - // Since ProtoStep8 (#issue 108) - if (size >= (unsigned int) dataOffset) - { - PutUINT(fillPoly -> x_origin, buffer + 16, bigEndian); - PutUINT(fillPoly -> y_origin, buffer + 18, bigEndian); - } - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void FillPolyStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - FillPolyMessage *fillPoly = (FillPolyMessage *) message; - - *logofs << name() << ": Identity drawable " << fillPoly -> drawable - << ", gcontext " << fillPoly -> gcontext << ", shape " - << fillPoly -> shape << ", mode " << fillPoly -> mode - << fillPoly -> size_ << ", x_origin " << fillPoly -> x_origin - << ", y_origin " << fillPoly -> y_origin << ".\n" - << logofs_flush; - #endif -} - -void FillPolyStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Fields shape, mode. - // - - md5_append(md5_state_, buffer + 12, 2); -} - -void FillPolyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - FillPolyMessage *fillPoly = (FillPolyMessage *) message; - FillPolyMessage *cachedFillPoly = (FillPolyMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << fillPoly -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(fillPoly -> drawable, clientCache -> drawableCache); - - cachedFillPoly -> drawable = fillPoly -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << fillPoly -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(fillPoly -> gcontext, clientCache -> gcCache); - - cachedFillPoly -> gcontext = fillPoly -> gcontext; - - // Since ProtoStep8 (#issue 108) - if (fillPoly -> size_ >= dataOffset) - { - #ifdef TEST - *logofs << name() << ": Encoding value " << fillPoly -> x_origin - << " as x_origin field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(fillPoly -> x_origin, 16, - *clientCache -> fillPolyXAbsCache[0], 8); - - cachedFillPoly -> x_origin = fillPoly -> x_origin; - - #ifdef TEST - *logofs << name() << ": Encoding value " << fillPoly -> y_origin - << " as y_origin field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(fillPoly -> y_origin, 16, - *clientCache -> fillPolyYAbsCache[0], 8); - - cachedFillPoly -> y_origin = fillPoly -> y_origin; - } -} - -void FillPolyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - FillPolyMessage *fillPoly = (FillPolyMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(fillPoly -> drawable, clientCache -> drawableCache); - - #ifdef TEST - *logofs << name() << ": Decoded value " << fillPoly -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(fillPoly -> gcontext, clientCache -> gcCache); - - #ifdef TEST - *logofs << name() << ": Decoded value " << fillPoly -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - // Since ProtoStep8 (#issue 108) - if (fillPoly -> size_ >= dataOffset) - { - unsigned int value; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache -> fillPolyXAbsCache[0], 8); - - fillPoly -> x_origin = value; - - #ifdef TEST - *logofs << name() << ": Decoded value " << fillPoly -> x_origin - << " as x_origin field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache -> fillPolyYAbsCache[0], 8); - - fillPoly -> y_origin = value; - - #ifdef TEST - *logofs << name() << ": Decoded value " << fillPoly -> y_origin - << " as y_origin field.\n" << logofs_flush; - #endif - } -} - - diff --git a/nxcomp/FillPoly.h b/nxcomp/FillPoly.h deleted file mode 100644 index 4ceb96c09..000000000 --- a/nxcomp/FillPoly.h +++ /dev/null @@ -1,200 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef FillPoly_H -#define FillPoly_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define FILLPOLY_ENABLE_CACHE 1 -#define FILLPOLY_ENABLE_DATA 0 -#define FILLPOLY_ENABLE_SPLIT 0 -#define FILLPOLY_ENABLE_COMPRESS 0 - -#define FILLPOLY_DATA_LIMIT 512 - -#define FILLPOLY_CACHE_SLOTS 2000 -#define FILLPOLY_CACHE_THRESHOLD 3 -#define FILLPOLY_CACHE_LOWER_THRESHOLD 1 - -#define FILLPOLY_DATA_OFFSET_IF_PROTO_STEP_8 20 - -// -// The message class. -// - -class FillPolyMessage : public Message -{ - friend class FillPolyStore; - - public: - - FillPolyMessage() - { - } - - ~FillPolyMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char shape; - unsigned char mode; - unsigned int drawable; - unsigned int gcontext; - - unsigned short x_origin; - unsigned short y_origin; -}; - -class FillPolyStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - FillPolyStore() : MessageStore() - { - enableCache = FILLPOLY_ENABLE_CACHE; - enableData = FILLPOLY_ENABLE_DATA; - enableSplit = FILLPOLY_ENABLE_SPLIT; - enableCompress = FILLPOLY_ENABLE_COMPRESS; - - dataLimit = FILLPOLY_DATA_LIMIT; - - // Since ProtoStep8 (#issue 108) - dataOffset = FILLPOLY_DATA_OFFSET_IF_PROTO_STEP_8; - - cacheSlots = FILLPOLY_CACHE_SLOTS; - cacheThreshold = FILLPOLY_CACHE_THRESHOLD; - cacheLowerThreshold = FILLPOLY_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~FillPolyStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "FillPoly"; - } - - virtual unsigned char opcode() const - { - return X_FillPoly; - } - - virtual unsigned int storage() const - { - return sizeof(FillPolyMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new FillPolyMessage(); - } - - virtual Message *create(const Message &message) const - { - return new FillPolyMessage((const FillPolyMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (FillPolyMessage *) message; - } - - virtual int identitySize(const unsigned char *buffer, unsigned int size) - { - // Since ProtoStep8 (#issue 108) - return (size >= FILLPOLY_DATA_OFFSET_IF_PROTO_STEP_8 ? - FILLPOLY_DATA_OFFSET_IF_PROTO_STEP_8 : size); - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* FillPoly_H */ diff --git a/nxcomp/Fork.cpp b/nxcomp/Fork.cpp deleted file mode 100644 index 0120cb4a6..000000000 --- a/nxcomp/Fork.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include - -#include "Fork.h" -#include "Misc.h" -#include "Timestamp.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Only on Cygwin, retry n times waiting a -// given amount of milliseconds after each -// attempt. -// - -#define RETRY_LIMIT 30 -#define RETRY_TIMEOUT 1000 - -int Fork() -{ - #ifdef __CYGWIN32__ - - int limit = RETRY_LIMIT; - int timeout = RETRY_TIMEOUT; - - #else - - int limit = 1; - int timeout = 0; - - #endif - - int pid = 0; - - for (int i = 0; i < limit; i++) - { - #ifdef TEST - *logofs << "Fork: Trying at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - // - // It could optionally try again only if the - // error code is 11, 'Resource temporarily - // unavailable'. - // - - if ((pid = fork()) >= 0) - { - break; - } - else if (i < limit - 1) - { - #ifdef WARNING - *logofs << "Fork: WARNING! Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'. Retrying...\n" << logofs_flush; - #endif - - usleep(timeout * 1000); - } - } - - #ifdef TEST - - if (pid <= 0) - { - *logofs << "Fork: Returning at " << strMsTimestamp() - << ".\n" << logofs_flush; - } - - #endif - - return pid; -} diff --git a/nxcomp/Fork.h b/nxcomp/Fork.h deleted file mode 100644 index 94238ed90..000000000 --- a/nxcomp/Fork.h +++ /dev/null @@ -1,31 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Try again if the fork() fails, as it can happen -// often on Cygwin. -// - -extern int Fork(); diff --git a/nxcomp/FreeCache.h b/nxcomp/FreeCache.h deleted file mode 100644 index bf5c801e5..000000000 --- a/nxcomp/FreeCache.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef FreeCache_H -#define FreeCache_H - -#include "IntCache.h" - -class FreeCache : public IntCache -{ - public: - - FreeCache(unsigned int size) - - : IntCache(size) - { - } -}; - -#endif /* FreeCache_H */ diff --git a/nxcomp/GenericChannel.cpp b/nxcomp/GenericChannel.cpp deleted file mode 100644 index 6fc049e70..000000000 --- a/nxcomp/GenericChannel.cpp +++ /dev/null @@ -1,491 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include - -#include "GenericChannel.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "StaticCompressor.h" - -#include "Statistics.h" -#include "Proxy.h" - -extern Proxy *proxy; - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Log the important tracepoints related -// to writing packets to the peer proxy. -// - -#undef FLUSH - -// -// Define this to log when a channel -// is created or destroyed. -// - -#undef REFERENCES - -// -// Here are the static members. -// - -#ifdef REFERENCES - -int GenericChannel::references_ = 0; - -#endif - -GenericChannel::GenericChannel(Transport *transport, StaticCompressor *compressor) - - : Channel(transport, compressor), readBuffer_(transport_, this) -{ - #ifdef REFERENCES - *logofs << "GenericChannel: Created new object at " - << this << " for FD#" << fd_ << " out of " - << ++references_ << " allocated channels.\n" - << logofs_flush; - #endif -} - -GenericChannel::~GenericChannel() -{ - #ifdef REFERENCES - *logofs << "GenericChannel: Deleted object at " - << this << " for FD#" << fd_ << " out of " - << --references_ << " allocated channels.\n" - << logofs_flush; - #endif -} - -// -// Beginning of handleRead(). -// - -int GenericChannel::handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, - unsigned int length) -{ - #ifdef TEST - *logofs << "handleRead: Called for FD#" << fd_ - << " with " << encodeBuffer.getLength() - << " bytes already encoded.\n" - << logofs_flush; - #endif - - // - // Pointer to located message and - // its size in bytes. - // - - const unsigned char *inputMessage; - unsigned int inputLength; - - // - // Tag message as generic data in compression - // routine. Opcode is not actually transferred - // over the network. - // - - unsigned char inputOpcode = X_NXInternalGenericData; - - #if defined(TEST) || defined(INFO) - *logofs << "handleRead: Trying to read from FD#" - << fd_ << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - int result = readBuffer_.readMessage(); - - #ifdef DEBUG - *logofs << "handleRead: Read result on FD#" << fd_ - << " is " << result << ".\n" - << logofs_flush; - #endif - - if (result < 0) - { - // - // Let the proxy close the channel. - // - - return -1; - } - else if (result == 0) - { - #if defined(TEST) || defined(INFO) - - *logofs << "handleRead: PANIC! No data read from FD#" - << fd_ << " while encoding messages.\n" - << logofs_flush; - - HandleCleanup(); - - #endif - - return 0; - } - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "handleRead: Encoding messages for FD#" << fd_ - << " with " << readBuffer_.getLength() << " bytes " - << "in the buffer.\n" << logofs_flush; - #endif - - // - // Divide the available data in multiple - // messages and encode them one by one. - // - - if (proxy -> handleAsyncSwitch(fd_) < 0) - { - return -1; - } - - while ((inputMessage = readBuffer_.getMessage(inputLength)) != NULL) - { - encodeBuffer.encodeValue(inputLength, 32, 14); - - if (isCompressed() == 1) - { - unsigned int compressedDataSize = 0; - unsigned char *compressedData = NULL; - - if (handleCompress(encodeBuffer, inputOpcode, 0, - inputMessage, inputLength, compressedData, - compressedDataSize) < 0) - { - return -1; - } - } - else - { - encodeBuffer.encodeMemory(inputMessage, inputLength); - } - - int bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleRead: Handled generic data for FD#" << fd_ - << ". " << inputLength << " bytes in, " << bits << " bits (" - << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; - #endif - - addProtocolBits(inputLength << 3, bits); - - if (isPrioritized() == 1) - { - priority_++; - } - - } // End of while ((inputMessage = readBuffer_.getMessage(inputLength)) != NULL) ... - - // - // All data has been read from the read buffer. - // We still need to mark the end of the encode - // buffer just before sending the frame. This - // allows us to accommodate multiple reads in - // a single frame. - // - - if (priority_ > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleRead: WARNING! Requesting flush " - << "because of " << priority_ << " prioritized " - << "messages for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - if (proxy -> handleAsyncPriority() < 0) - { - return -1; - } - - // - // Reset the priority flag. - // - - priority_ = 0; - } - - // - // Flush if we produced enough data. - // - - if (proxy -> canAsyncFlush() == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleRead: WARNING! Requesting flush " - << "because of enough data or timeout on the " - << "proxy link.\n" << logofs_flush; - #endif - - if (proxy -> handleAsyncFlush() < 0) - { - return -1; - } - } - - #if defined(TEST) || defined(INFO) - - if (transport_ -> pending() != 0 || - readBuffer_.checkMessage() != 0) - { - *logofs << "handleRead: PANIC! Buffer for X descriptor FD#" - << fd_ << " has " << transport_ -> pending() - << " bytes to read.\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - // - // Reset the read buffer. - // - - readBuffer_.fullReset(); - - return 1; -} - -// -// End of handleRead(). -// - -// -// Beginning of handleWrite(). -// - -int GenericChannel::handleWrite(const unsigned char *message, unsigned int length) -{ - #ifdef TEST - *logofs << "handleWrite: Called for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - // - // Create the buffer from which to - // decode messages. - // - - DecodeBuffer decodeBuffer(message, length); - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "handleWrite: Decoding messages for FD#" << fd_ - << " with " << length << " bytes in the buffer.\n" - << logofs_flush; - #endif - - unsigned char *outputMessage; - unsigned int outputLength; - - // - // Tag message as generic data - // in decompression. - // - - unsigned char outputOpcode = X_NXInternalGenericData; - - for (;;) - { - decodeBuffer.decodeValue(outputLength, 32, 14); - - if (outputLength == 0) - { - break; - } - - if (isCompressed() == 1) - { - if (writeBuffer_.getAvailable() < outputLength || - (int) outputLength >= control -> TransportFlushBufferSize) - { - #ifdef DEBUG - *logofs << "handleWrite: Using scratch buffer for " - << "generic data with size " << outputLength << " and " - << writeBuffer_.getLength() << " bytes in buffer.\n" - << logofs_flush; - #endif - - outputMessage = writeBuffer_.addScratchMessage(outputLength); - } - else - { - outputMessage = writeBuffer_.addMessage(outputLength); - } - - const unsigned char *compressedData = NULL; - unsigned int compressedDataSize = 0; - - int decompressed = handleDecompress(decodeBuffer, outputOpcode, 0, - outputMessage, outputLength, compressedData, - compressedDataSize); - if (decompressed < 0) - { - return -1; - } - } - else - { - #ifdef DEBUG - *logofs << "handleWrite: Using scratch buffer for " - << "generic data with size " << outputLength << " and " - << writeBuffer_.getLength() << " bytes in buffer.\n" - << logofs_flush; - #endif - - writeBuffer_.addScratchMessage((unsigned char *) - decodeBuffer.decodeMemory(outputLength), outputLength); - } - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleWrite: Handled generic data for FD#" << fd_ - << ". " << outputLength << " bytes out.\n" - << logofs_flush; - #endif - - handleFlush(flush_if_needed); - } - - // - // Write any remaining data to socket. - // - - if (handleFlush(flush_if_any) < 0) - { - return -1; - } - - return 1; -} - -// -// End of handleWrite(). -// - -// -// Other members. -// - -int GenericChannel::handleCompletion(EncodeBuffer &encodeBuffer) -{ - // - // Add the bits telling to the remote - // that all data in the frame has been - // encoded. - // - - if (encodeBuffer.getLength() > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleCompletion: Writing completion bits with " - << encodeBuffer.getLength() << " bytes encoded " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeValue(0, 32, 14); - - return 1; - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "handleCompletion: PANIC! No completion to write " - << "for FD#" << fd_ << ".\n" << logofs_flush; - - HandleCleanup(); - } - #endif - - return 0; -} - -int GenericChannel::handleConfiguration() -{ - #ifdef TEST - *logofs << "GenericChannel: Setting new buffer parameters.\n" - << logofs_flush; - #endif - - readBuffer_.setSize(control -> GenericInitialReadSize, - control -> GenericMaximumBufferSize); - - writeBuffer_.setSize(control -> TransportGenericBufferSize, - control -> TransportGenericBufferThreshold, - control -> TransportMaximumBufferSize); - - transport_ -> setSize(control -> TransportGenericBufferSize, - control -> TransportGenericBufferThreshold, - control -> TransportMaximumBufferSize); - - return 1; -} - -int GenericChannel::handleFinish() -{ - #ifdef TEST - *logofs << "GenericChannel: Finishing channel for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - congestion_ = 0; - priority_ = 0; - - finish_ = 1; - - transport_ -> fullReset(); - - return 1; -} - -int GenericChannel::setReferences() -{ - #ifdef TEST - *logofs << "GenericChannel: Initializing the static " - << "members for the generic channels.\n" - << logofs_flush; - #endif - - #ifdef REFERENCES - - references_ = 0; - - #endif - - return 1; -} diff --git a/nxcomp/GenericChannel.h b/nxcomp/GenericChannel.h deleted file mode 100644 index 3df18f444..000000000 --- a/nxcomp/GenericChannel.h +++ /dev/null @@ -1,440 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef GenericChannel_H -#define GenericChannel_H - -#include "Channel.h" - -#include "Statistics.h" - -#include "GenericReadBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#undef TEST -#undef DEBUG - -// -// Define this to log a line when a channel -// is created or destroyed. -// - -#undef REFERENCES - -// -// This class implements the client -// side compression of X protocol. -// - -class GenericChannel : public Channel -{ - public: - - GenericChannel(Transport *transport, StaticCompressor *compressor); - - virtual ~GenericChannel(); - - virtual int handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, - unsigned int length); - - virtual int handleWrite(const unsigned char *message, unsigned int length); - - - virtual int handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, - T_store_action action, int position, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) - { - return 0; - } - - virtual int handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, - T_store_action action, int position, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) - { - return 0; - } - - - virtual int handleSplit(EncodeBuffer &encodeBuffer) - { - return 0; - } - - virtual int handleSplit(DecodeBuffer &decodeBuffer) - { - return 0; - } - - virtual int handleSplitEvent(EncodeBuffer &encodeBuffer, Split *split) - { - return 0; - } - - virtual int handleSplitEvent(DecodeBuffer &decodeBuffer) - { - return 0; - } - - virtual int handleMotion(EncodeBuffer &encodeBuffer) - { - return 0; - } - - virtual int handleCompletion(EncodeBuffer &encodeBuffer); - - virtual int handleConfiguration(); - - virtual int handleFinish(); - - virtual int handleAsyncEvents() - { - return 0; - } - - virtual int needSplit() const - { - return 0; - } - - virtual int needMotion() const - { - return 0; - } - - virtual T_channel_type getType() const = 0; - - // - // Initialize the static members. - // - - static int setReferences(); - - protected: - - // - // Generic channels are considered to be - // in congestion state as soon as the - // socket is blocked for write. - // - - virtual int isCongested() - { - return (transport_ -> blocked() == 1); - } - - virtual int isReliable() - { - return 0; - } - - // - // Model generic channels' encoding and - // decoding policy. - // - - virtual int isCompressed() = 0; - - // - // Return true if the channel contains - // time sensitive data. - // - - virtual int isPrioritized() = 0; - - // - // Record the protocol bits for the - // specific service. - // - - virtual void addProtocolBits(unsigned int bitsIn, unsigned int bitsOut) = 0; - - // - // Channel's own read buffer. - // - - GenericReadBuffer readBuffer_; - - private: - - // - // Keep track of object's creation - // and deletion. - // - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -class CupsChannel : public GenericChannel -{ - public: - - CupsChannel(Transport *transport, StaticCompressor *compressor) - - : GenericChannel(transport, compressor) - { - } - - virtual ~CupsChannel() - { - } - - protected: - - virtual T_channel_type getType() const - { - return channel_cups; - } - - virtual int isCompressed() - { - // Since ProtoStep8 (#issue 108) - return 0; - } - - virtual int isPrioritized() - { - return 0; - } - - virtual void addProtocolBits(unsigned int bitsIn, - unsigned int bitsOut) - { - statistics -> addCupsBits(bitsIn, bitsOut); - } -}; - -class SmbChannel : public GenericChannel -{ - public: - - SmbChannel(Transport *transport, StaticCompressor *compressor) - - : GenericChannel(transport, compressor) - { - } - - virtual ~SmbChannel() - { - } - - protected: - - virtual T_channel_type getType() const - { - return channel_smb; - } - - virtual int isCompressed() - { - // Since ProtoStep8 (#issue 108) - return 0; - } - - virtual int isPrioritized() - { - return 0; - } - - virtual void addProtocolBits(unsigned int bitsIn, - unsigned int bitsOut) - { - statistics -> addSmbBits(bitsIn, bitsOut); - } -}; - -class MediaChannel : public GenericChannel -{ - public: - - MediaChannel(Transport *transport, StaticCompressor *compressor) - - : GenericChannel(transport, compressor) - { - } - - virtual ~MediaChannel() - { - } - - protected: - - virtual T_channel_type getType() const - { - return channel_media; - } - - // - // Don't try to compress the media data. - // - - virtual int isCompressed() - { - return 0; - } - - // - // Reduce the latency of media channels - // by setting them as prioritized, even - // if this will take away bandwidth from - // the X channels. - // - - virtual int isPrioritized() - { - return 1; - } - - virtual void addProtocolBits(unsigned int bitsIn, - unsigned int bitsOut) - { - statistics -> addMediaBits(bitsIn, bitsOut); - } -}; - -class HttpChannel : public GenericChannel -{ - public: - - HttpChannel(Transport *transport, StaticCompressor *compressor) - - : GenericChannel(transport, compressor) - { - } - - virtual ~HttpChannel() - { - } - - protected: - - virtual T_channel_type getType() const - { - return channel_http; - } - - virtual int isCompressed() - { - // Since ProtoStep8 (#issue 108) - return 0; - } - - virtual int isPrioritized() - { - return 0; - } - - virtual void addProtocolBits(unsigned int bitsIn, - unsigned int bitsOut) - { - statistics -> addHttpBits(bitsIn, bitsOut); - } -}; - -class FontChannel : public GenericChannel -{ - public: - - FontChannel(Transport *transport, StaticCompressor *compressor) - - : GenericChannel(transport, compressor) - { - } - - virtual ~FontChannel() - { - } - - protected: - - virtual T_channel_type getType() const - { - return channel_font; - } - - virtual int isCompressed() - { - // Since ProtoStep8 (#issue 108) - return 0; - } - - virtual int isPrioritized() - { - return 1; - } - - virtual void addProtocolBits(unsigned int bitsIn, - unsigned int bitsOut) - { - statistics -> addFontBits(bitsIn, bitsOut); - } -}; - -class SlaveChannel : public GenericChannel -{ - public: - - SlaveChannel(Transport *transport, StaticCompressor *compressor) - - : GenericChannel(transport, compressor) - { - } - - virtual ~SlaveChannel() - { - } - - protected: - - virtual T_channel_type getType() const - { - return channel_slave; - } - - virtual int isCompressed() - { - return 0; - } - - virtual int isPrioritized() - { - return 0; - } - - virtual void addProtocolBits(unsigned int bitsIn, - unsigned int bitsOut) - { - statistics -> addSlaveBits(bitsIn, bitsOut); - } -}; - -#endif /* GenericChannel_H */ diff --git a/nxcomp/GenericReadBuffer.cpp b/nxcomp/GenericReadBuffer.cpp deleted file mode 100644 index 337ae2f61..000000000 --- a/nxcomp/GenericReadBuffer.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "GenericReadBuffer.h" - -#include "GenericChannel.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -unsigned int GenericReadBuffer::suggestedLength(unsigned int pendingLength) -{ - // - // Always read the initial read size. - // - - return 0; -} - -int GenericReadBuffer::locateMessage(const unsigned char *start, - const unsigned char *end, - unsigned int &controlLength, - unsigned int &dataLength, - unsigned int &trailerLength) -{ - // - // We don't care about the endianess - // in generic channels. - // - - unsigned int size = end - start; - - #ifdef TEST - *logofs << "GenericReadBuffer: Locating message for FD#" - << transport_ -> fd() << " with " << size - << " bytes.\n" << logofs_flush; - #endif - - if (size == 0) - { - remaining_ = 1; - - return 0; - } - - dataLength = size; - - controlLength = 0; - trailerLength = 0; - - remaining_ = 0; - - return 1; -} diff --git a/nxcomp/GenericReadBuffer.h b/nxcomp/GenericReadBuffer.h deleted file mode 100644 index 5ea4d939d..000000000 --- a/nxcomp/GenericReadBuffer.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef GenericReadBuffer_H -#define GenericReadBuffer_H - -#include "ReadBuffer.h" -#include "Control.h" - -class GenericChannel; - -class GenericReadBuffer : public ReadBuffer -{ - public: - - GenericReadBuffer(Transport *transport, GenericChannel *channel) - - : ReadBuffer(transport), channel_(channel) - { - } - - virtual ~GenericReadBuffer() - { - } - - protected: - - virtual unsigned int suggestedLength(unsigned int pendingLength); - - virtual int locateMessage(const unsigned char *start, - const unsigned char *end, - unsigned int &controlLength, - unsigned int &dataLength, - unsigned int &trailerLength); - - GenericChannel *channel_; -}; - -#endif /* GenericReadBuffer_H */ diff --git a/nxcomp/GenericReply.cpp b/nxcomp/GenericReply.cpp deleted file mode 100644 index 3d9a0d638..000000000 --- a/nxcomp/GenericReply.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "GenericReply.h" - -#include "ServerCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -GenericReplyStore::GenericReplyStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = GENERICREPLY_ENABLE_CACHE; - enableData = GENERICREPLY_ENABLE_DATA; - enableSplit = GENERICREPLY_ENABLE_SPLIT; - - // Since ProtoStep7 (#issue 108) - enableCompress = GENERICREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = GENERICREPLY_DATA_LIMIT; - dataOffset = GENERICREPLY_DATA_OFFSET; - - cacheSlots = GENERICREPLY_CACHE_SLOTS; - cacheThreshold = GENERICREPLY_CACHE_THRESHOLD; - cacheLowerThreshold = GENERICREPLY_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -GenericReplyStore::~GenericReplyStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int GenericReplyStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ServerCache *serverCache = (ServerCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message identity.\n" - << logofs_flush; - #endif - - encodeBuffer.encodeValue(GetULONG(buffer + 4, bigEndian), 32, 15); - - encodeBuffer.encodeCachedValue(*(buffer + 1), 8, - serverCache -> genericReplyCharCache); - - for (unsigned int i = 0; i < 6; i++) - { - encodeBuffer.encodeCachedValue(GetULONG(buffer + i * 4 + 8, bigEndian), 32, - *serverCache -> genericReplyIntCache[i]); - } - - #ifdef DEBUG - *logofs << name() << ": Encoded full message identity.\n" - << logofs_flush; - #endif - - return 1; -} - -int GenericReplyStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ServerCache *serverCache = (ServerCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message identity.\n" - << logofs_flush; - #endif - - decodeBuffer.decodeValue(size, 32, 15); - - size = 32 + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - decodeBuffer.decodeCachedValue(*(buffer + 1), 8, - serverCache -> genericReplyCharCache); - - unsigned int value; - - for (unsigned int i = 0; i < 6; i++) - { - decodeBuffer.decodeCachedValue(value, 32, - *serverCache -> genericReplyIntCache[i]); - - PutULONG(value, buffer + i * 4 + 8, bigEndian); - } - - #ifdef DEBUG - *logofs << name() << ": Decoded full message identity.\n" - << logofs_flush; - #endif - - return 1; -} - -int GenericReplyStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GenericReplyMessage *genericReply = (GenericReplyMessage *) message; - - genericReply -> byte_data = *(buffer + 1); - - for (int i = 0; i < 12; i++) - { - genericReply -> short_data[i] = GetUINT(buffer + i * 2 + 8, bigEndian); - } - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int GenericReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GenericReplyMessage *genericReply = (GenericReplyMessage *) message; - - *(buffer + 1) = genericReply -> byte_data; - - for (int i = 0; i < 12; i++) - { - PutUINT(genericReply -> short_data[i], buffer + i * 2 + 8, bigEndian); - } - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void GenericReplyStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - GenericReplyMessage *genericReply = (GenericReplyMessage *) message; - - *logofs << name() << ": Identity byte_data " - << (unsigned) genericReply -> byte_data; - - for (int i = 0; i < 12; i++) - { - *logofs << ", short_data[" << i << "]" - << (unsigned) genericReply -> short_data[i]; - } - - *logofs << ", size " << genericReply -> size_ << ".\n"; - - #endif -} - -void GenericReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -} - -void GenericReplyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - // - // Encode the variant part. - // - - GenericReplyMessage *genericReply = (GenericReplyMessage *) message; - GenericReplyMessage *cachedGenericReply = (GenericReplyMessage *) cachedMessage; - - ServerCache *serverCache = (ServerCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " - << (unsigned int) genericReply -> byte_data - << " as byte_data field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(genericReply -> byte_data, 8, - serverCache -> genericReplyCharCache); - - cachedGenericReply -> byte_data = genericReply -> byte_data; - - for (unsigned int i = 0; i < 12; i++) - { - #ifdef TEST - *logofs << name() << ": Encoding value " << genericReply -> short_data[i] - << " as short_data[" << i << "] field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(genericReply -> short_data[i], 16, - *serverCache -> genericReplyIntCache[i]); - - cachedGenericReply -> short_data[i] = genericReply -> short_data[i]; - } -} - -void GenericReplyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - // - // Decode the variant part. - // - - GenericReplyMessage *genericReply = (GenericReplyMessage *) message; - - ServerCache *serverCache = (ServerCache *) channelCache; - - decodeBuffer.decodeCachedValue(genericReply -> byte_data, 8, - serverCache -> genericReplyCharCache); - - #ifdef TEST - *logofs << name() << ": Decoded value " - << (unsigned int) genericReply -> byte_data - << " as byte_data field.\n" << logofs_flush; - #endif - - unsigned int value; - - for (unsigned int i = 0; i < 12; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *serverCache -> genericReplyIntCache[i]); - - genericReply -> short_data[i] = (unsigned short) value; - - #ifdef TEST - *logofs << name() << ": Decoded value " << genericReply -> short_data[i] - << " as short_data[" << i << "] field.\n" << logofs_flush; - #endif - } -} diff --git a/nxcomp/GenericReply.h b/nxcomp/GenericReply.h deleted file mode 100644 index e899b8467..000000000 --- a/nxcomp/GenericReply.h +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef GenericReply_H -#define GenericReply_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define GENERICREPLY_ENABLE_CACHE 1 -#define GENERICREPLY_ENABLE_DATA 1 -#define GENERICREPLY_ENABLE_SPLIT 0 - -#define GENERICREPLY_DATA_LIMIT 1048576 - 32 -#define GENERICREPLY_DATA_OFFSET 32 - -#define GENERICREPLY_CACHE_SLOTS 400 -#define GENERICREPLY_CACHE_THRESHOLD 5 -#define GENERICREPLY_CACHE_LOWER_THRESHOLD 1 - -#define GENERICREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -// -// The message class. -// - -class GenericReplyMessage : public Message -{ - friend class GenericReplyStore; - - public: - - GenericReplyMessage() - { - } - - ~GenericReplyMessage() - { - } - - // - // Put here the fields which constitute the - // 'identity' part of the message. Starting - // from protocol level 3 we use short data - // to increase cache efficiency. - // - - private: - - unsigned char byte_data; - unsigned int int_data[6]; - unsigned short short_data[12]; -}; - -class GenericReplyStore : public MessageStore -{ - public: - - GenericReplyStore(StaticCompressor *compressor); - - virtual ~GenericReplyStore(); - - virtual const char *name() const - { - return "GenericReply"; - } - - virtual unsigned char opcode() const - { - return X_NXInternalGenericReply; - } - - virtual unsigned int storage() const - { - return sizeof(GenericReplyMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new GenericReplyMessage(); - } - - virtual Message *create(const Message &message) const - { - return new GenericReplyMessage((const GenericReplyMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (GenericReplyMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* GenericReply_H */ diff --git a/nxcomp/GenericRequest.cpp b/nxcomp/GenericRequest.cpp deleted file mode 100644 index 5c342fcf7..000000000 --- a/nxcomp/GenericRequest.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "GenericRequest.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -GenericRequestStore::GenericRequestStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = GENERICREQUEST_ENABLE_CACHE; - enableData = GENERICREQUEST_ENABLE_DATA; - enableSplit = GENERICREQUEST_ENABLE_SPLIT; - - // Since ProtoStep7 (#issue 108) - enableCompress = GENERICREQUEST_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = GENERICREQUEST_DATA_LIMIT; - dataOffset = GENERICREQUEST_DATA_OFFSET; - - cacheSlots = GENERICREQUEST_CACHE_SLOTS; - cacheThreshold = GENERICREQUEST_CACHE_THRESHOLD; - cacheLowerThreshold = GENERICREQUEST_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -GenericRequestStore::~GenericRequestStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int GenericRequestStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; - #endif - - encodeBuffer.encodeValue(size >> 2, 16, 10); - - encodeBuffer.encodeCachedValue(*(buffer + 1), 8, - clientCache -> genericRequestOpcodeCache); - - for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) - { - #ifdef DEBUG - *logofs << name() << ": Encoding data[" << i << "] " - << "at position " << i * 2 + 4 << " with value " - << GetUINT(buffer + (i * 2) + 4, bigEndian) - << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(GetUINT(buffer + (i * 2) + 4, bigEndian), 16, - *clientCache -> genericRequestDataCache[i]); - } - - #ifdef DEBUG - *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int GenericRequestStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; - #endif - - decodeBuffer.decodeValue(size, 16, 10); - - size <<= 2; - - buffer = writeBuffer -> addMessage(size); - - decodeBuffer.decodeCachedValue(*(buffer + 1), 8, - clientCache -> genericRequestOpcodeCache); - - unsigned int value; - - for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache -> genericRequestDataCache[i]); - - #ifdef DEBUG - *logofs << name() << ": Decoding data[" << i << "] " - << "at position " << i * 2 + 4 << " with value " - << value << ".\n" << logofs_flush; - #endif - - PutUINT(value, buffer + 4 + (i * 2), bigEndian); - } - - #ifdef DEBUG - *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int GenericRequestStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; - - genericRequest -> opcode = *(buffer + 1); - - for (unsigned int i = 0; i < 8; i++) - { - if ((i * 2 + 4) < size) - { - genericRequest -> data[i] = GetUINT(buffer + i * 2 + 4, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed data[" << i << "] " - << "with value " << genericRequest -> data[i] - << ".\n" << logofs_flush; - #endif - } - else - { - genericRequest -> data[i] = 0; - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int GenericRequestStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; - - *(buffer + 1) = genericRequest -> opcode; - - for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) - { - #ifdef DEBUG - *logofs << name() << ": Unparsed data[" << i << "] " - << "with value " << genericRequest -> data[i] - << ".\n" << logofs_flush; - #endif - - PutUINT(genericRequest -> data[i], buffer + i * 2 + 4, bigEndian); - } - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void GenericRequestStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; - - *logofs << name() << ": Identity opcode " << (unsigned) genericRequest -> opcode; - - for (int i = 0; i < 8; i++) - { - *logofs << ", data[" << i << "] " << genericRequest -> data[i]; - } - - *logofs << ", size " << genericRequest -> size_ << ".\n" << logofs_flush; - - #endif -} - -void GenericRequestStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // As data offset can be beyond the real end of - // the message, we need to include the message's - // size or we will match any message whose size - // is less or equal to the data offset. - // - - md5_append(md5_state_, buffer + 2, 2); -} - -void GenericRequestStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - // - // Encode the variant part. - // - - GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; - GenericRequestMessage *cachedGenericRequest = (GenericRequestMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Updating value " - << (unsigned) genericRequest -> opcode - << " as opcode field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue((unsigned int) genericRequest -> opcode, 8, - clientCache -> genericRequestOpcodeCache); - - cachedGenericRequest -> opcode = genericRequest -> opcode; - - for (int i = 0; i < 8 && (i * 2 + 4) < genericRequest -> size_; i++) - { - #ifdef TEST - *logofs << name() << ": Updating data[" << i << "] " - << "with value " << genericRequest -> data[i] - << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue((unsigned int) genericRequest -> data[i], 16, - *clientCache -> genericRequestDataCache[i]); - - cachedGenericRequest -> data[i] = genericRequest -> data[i]; - } -} - -void GenericRequestStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(genericRequest -> opcode, 8, - clientCache -> genericRequestOpcodeCache); - - #ifdef TEST - *logofs << name() << ": Updated value " - << (unsigned) genericRequest -> opcode - << " as opcode field.\n" << logofs_flush; - #endif - - unsigned int value; - - for (int i = 0; i < 8 && (i * 2 + 4) < genericRequest -> size_; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache -> genericRequestDataCache[i]); - - genericRequest -> data[i] = (unsigned short) value; - - #ifdef TEST - *logofs << name() << ": Updated data[" << i << "] " - << "with value " << genericRequest -> data[i] - << ".\n" << logofs_flush; - #endif - } -} diff --git a/nxcomp/GenericRequest.h b/nxcomp/GenericRequest.h deleted file mode 100644 index 13ffea718..000000000 --- a/nxcomp/GenericRequest.h +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef GenericRequest_H -#define GenericRequest_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define GENERICREQUEST_ENABLE_CACHE 1 -#define GENERICREQUEST_ENABLE_DATA 1 -#define GENERICREQUEST_ENABLE_SPLIT 0 - -#define GENERICREQUEST_DATA_LIMIT 262144 - 20 -#define GENERICREQUEST_DATA_OFFSET 20 - -#define GENERICREQUEST_CACHE_SLOTS 400 -#define GENERICREQUEST_CACHE_THRESHOLD 5 -#define GENERICREQUEST_CACHE_LOWER_THRESHOLD 1 - -#define GENERICREQUEST_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -// -// The message class. -// - -class GenericRequestMessage : public Message -{ - friend class GenericRequestStore; - - public: - - GenericRequestMessage() - { - } - - ~GenericRequestMessage() - { - } - - // - // Note that we consider for this message a data offset - // of 4 (or 20 starting from protocol 3). Bytes from 9 - // to 20, if present, are taken as part of identity and - // encoded through an array of int caches. - // - - private: - - unsigned char opcode; - unsigned short data[8]; -}; - -class GenericRequestStore : public MessageStore -{ - public: - - GenericRequestStore(StaticCompressor *compressor); - - virtual ~GenericRequestStore(); - - virtual const char *name() const - { - return "GenericRequest"; - } - - virtual unsigned char opcode() const - { - return X_NXInternalGenericRequest; - } - - virtual unsigned int storage() const - { - return sizeof(GenericRequestMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new GenericRequestMessage(); - } - - virtual Message *create(const Message &message) const - { - return new GenericRequestMessage((const GenericRequestMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (GenericRequestMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* GenericRequest_H */ diff --git a/nxcomp/GetImage.cpp b/nxcomp/GetImage.cpp deleted file mode 100644 index f6481b61c..000000000 --- a/nxcomp/GetImage.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "GetImage.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int GetImageStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GetImageMessage *getImage = (GetImageMessage *) message; - - // - // Here is the fingerprint. - // - - getImage -> format = *(buffer + 1); - - #ifdef TEST - if (getImage -> format != 1 && getImage -> format != 2) - { - *logofs << name() << ": WARNING! Dirty value " << getImage -> format - << " for field format.\n" << logofs_flush; - } - #endif - - getImage -> drawable = GetULONG(buffer + 4, bigEndian); - - getImage -> x = GetUINT(buffer + 8, bigEndian); - getImage -> y = GetUINT(buffer + 10, bigEndian); - getImage -> width = GetUINT(buffer + 12, bigEndian); - getImage -> height = GetUINT(buffer + 14, bigEndian); - - getImage -> plane_mask = GetULONG(buffer + 16, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int GetImageStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GetImageMessage *getImage = (GetImageMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = getImage -> format; - - PutULONG(getImage -> drawable, buffer + 4, bigEndian); - - PutUINT(getImage -> x, buffer + 8, bigEndian); - PutUINT(getImage -> y, buffer + 10, bigEndian); - PutUINT(getImage -> width, buffer + 12, bigEndian); - PutUINT(getImage -> height, buffer + 14, bigEndian); - - PutULONG(getImage -> plane_mask, buffer + 16, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void GetImageStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - GetImageMessage *getImage = (GetImageMessage *) message; - - *logofs << name() << ": Identity format " << (unsigned) getImage -> format - << ", drawable " << getImage -> drawable << ", x " << getImage -> x - << ", y " << getImage -> y << ", width " << getImage -> width - << ", height " << getImage -> height << ", plane_mask " - << getImage -> plane_mask << ", size " << getImage -> size_ - << ".\n" << logofs_flush; - - #endif -} - -void GetImageStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 1, 1); - md5_append(md5_state_, buffer + 8, 2); - md5_append(md5_state_, buffer + 10, 2); - md5_append(md5_state_, buffer + 12, 2); - md5_append(md5_state_, buffer + 14, 2); - md5_append(md5_state_, buffer + 16, 4); -} - -void GetImageStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - GetImageMessage *getImage = (GetImageMessage *) message; - GetImageMessage *cachedGetImage = (GetImageMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << getImage -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(getImage -> drawable, clientCache -> drawableCache); - - cachedGetImage -> drawable = getImage -> drawable; -} - -void GetImageStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - GetImageMessage *getImage = (GetImageMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - getImage -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << getImage -> drawable - << " as drawable field.\n" << logofs_flush; - #endif -} - diff --git a/nxcomp/GetImage.h b/nxcomp/GetImage.h deleted file mode 100644 index 1c3558d14..000000000 --- a/nxcomp/GetImage.h +++ /dev/null @@ -1,190 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef GetImage_H -#define GetImage_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define GETIMAGE_ENABLE_CACHE 1 -#define GETIMAGE_ENABLE_DATA 0 -#define GETIMAGE_ENABLE_SPLIT 0 -#define GETIMAGE_ENABLE_COMPRESS 0 - -#define GETIMAGE_DATA_LIMIT 0 -#define GETIMAGE_DATA_OFFSET 20 - -#define GETIMAGE_CACHE_SLOTS 200 -#define GETIMAGE_CACHE_THRESHOLD 1 -#define GETIMAGE_CACHE_LOWER_THRESHOLD 0 - -// -// The message class. -// - -class GetImageMessage : public Message -{ - friend class GetImageStore; - - public: - - GetImageMessage() - { - } - - ~GetImageMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char format; - unsigned int drawable; - unsigned short int x; - unsigned short int y; - unsigned short int width; - unsigned short int height; - unsigned int plane_mask; -}; - -class GetImageStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - GetImageStore() : MessageStore() - { - enableCache = GETIMAGE_ENABLE_CACHE; - enableData = GETIMAGE_ENABLE_DATA; - enableSplit = GETIMAGE_ENABLE_SPLIT; - enableCompress = GETIMAGE_ENABLE_COMPRESS; - - dataLimit = GETIMAGE_DATA_LIMIT; - dataOffset = GETIMAGE_DATA_OFFSET; - - cacheSlots = GETIMAGE_CACHE_SLOTS; - cacheThreshold = GETIMAGE_CACHE_THRESHOLD; - cacheLowerThreshold = GETIMAGE_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~GetImageStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "GetImage"; - } - - virtual unsigned char opcode() const - { - return X_GetImage; - } - - virtual unsigned int storage() const - { - return sizeof(GetImageMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new GetImageMessage(); - } - - virtual Message *create(const Message &message) const - { - return new GetImageMessage((const GetImageMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (GetImageMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* GetImage_H */ diff --git a/nxcomp/GetImageReply.cpp b/nxcomp/GetImageReply.cpp deleted file mode 100644 index 9b99d38e7..000000000 --- a/nxcomp/GetImageReply.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "GetImageReply.h" - -#include "ServerCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -GetImageReplyStore::GetImageReplyStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = GETIMAGEREPLY_ENABLE_CACHE; - enableData = GETIMAGEREPLY_ENABLE_DATA; - enableSplit = GETIMAGEREPLY_ENABLE_SPLIT; - - // Since ProtoStep7 (#issue 108) - enableCompress = GETIMAGEREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = GETIMAGEREPLY_DATA_LIMIT; - dataOffset = GETIMAGEREPLY_DATA_OFFSET; - - cacheSlots = GETIMAGEREPLY_CACHE_SLOTS; - cacheThreshold = GETIMAGEREPLY_CACHE_THRESHOLD; - cacheLowerThreshold = GETIMAGEREPLY_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -GetImageReplyStore::~GetImageReplyStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int GetImageReplyStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; - - // - // Here is the fingerprint. - // - - getImageReply -> depth = *(buffer + 1); - - getImageReply -> visual = GetULONG(buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int GetImageReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = getImageReply -> depth; - - PutULONG(getImageReply -> visual, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void GetImageReplyStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; - - *logofs << name() << ": Identity depth " << (unsigned) getImageReply -> depth - << ", visual " << getImageReply -> visual << ", size " - << getImageReply -> size_ << ".\n"; - - #endif -} - -void GetImageReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Field depth. - // - - md5_append(md5_state_, buffer + 1, 1); -} - -void GetImageReplyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - // - // Encode the variant part. - // - - GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; - - ServerCache *serverCache = (ServerCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << getImageReply -> visual - << " as visual field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(getImageReply -> visual, 29, - serverCache -> visualCache); -} - -void GetImageReplyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - // - // Decode the variant part. - // - - GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; - - ServerCache *serverCache = (ServerCache *) channelCache; - - decodeBuffer.decodeCachedValue(getImageReply -> visual, 29, - serverCache -> visualCache); -} diff --git a/nxcomp/GetImageReply.h b/nxcomp/GetImageReply.h deleted file mode 100644 index d4f7c4267..000000000 --- a/nxcomp/GetImageReply.h +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef GetImageReply_H -#define GetImageReply_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define GETIMAGEREPLY_ENABLE_CACHE 1 -#define GETIMAGEREPLY_ENABLE_DATA 1 -#define GETIMAGEREPLY_ENABLE_SPLIT 0 - -#define GETIMAGEREPLY_DATA_LIMIT 1048576 - 32 -#define GETIMAGEREPLY_DATA_OFFSET 32 - -#define GETIMAGEREPLY_CACHE_SLOTS 1000 -#define GETIMAGEREPLY_CACHE_THRESHOLD 20 -#define GETIMAGEREPLY_CACHE_LOWER_THRESHOLD 2 - -#define GETIMAGEREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -// -// The message class. -// - -class GetImageReplyMessage : public Message -{ - friend class GetImageReplyStore; - - public: - - GetImageReplyMessage() - { - } - - ~GetImageReplyMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char depth; - unsigned int visual; -}; - -class GetImageReplyStore : public MessageStore -{ - public: - - GetImageReplyStore(StaticCompressor *compressor); - - virtual ~GetImageReplyStore(); - - virtual const char *name() const - { - return "GetImageReply"; - } - - virtual unsigned char opcode() const - { - return X_GetImage; - } - - virtual unsigned int storage() const - { - return sizeof(GetImageReplyMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new GetImageReplyMessage(); - } - - virtual Message *create(const Message &message) const - { - return new GetImageReplyMessage((const GetImageReplyMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (GetImageReplyMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* GetImageReply_H */ diff --git a/nxcomp/GetProperty.cpp b/nxcomp/GetProperty.cpp deleted file mode 100644 index a79ebd64a..000000000 --- a/nxcomp/GetProperty.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "GetProperty.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int GetPropertyStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GetPropertyMessage *getProperty = (GetPropertyMessage *) message; - - // - // Here is the fingerprint. - // - - getProperty -> property_delete = *(buffer + 1); - - getProperty -> window = GetULONG(buffer + 4, bigEndian); - getProperty -> property = GetULONG(buffer + 8, bigEndian); - getProperty -> type = GetULONG(buffer + 12, bigEndian); - getProperty -> long_offset = GetULONG(buffer + 16, bigEndian); - getProperty -> long_length = GetULONG(buffer + 20, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int GetPropertyStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - - GetPropertyMessage *getProperty = (GetPropertyMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = getProperty -> property_delete; - - PutULONG(getProperty -> window, buffer + 4, bigEndian); - PutULONG(getProperty -> property, buffer + 8, bigEndian); - PutULONG(getProperty -> type, buffer + 12, bigEndian); - PutULONG(getProperty -> long_offset, buffer + 16, bigEndian); - PutULONG(getProperty -> long_length, buffer + 20, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void GetPropertyStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - GetPropertyMessage *getProperty = (GetPropertyMessage *) message; - - *logofs << name() << ": Identity property_delete " << (unsigned int) getProperty -> property_delete - << ", window " << getProperty -> window << ", property " << getProperty -> property - << ", type " << getProperty -> type << ", long-offset " << getProperty -> long_offset - << ", long-length " << getProperty -> long_length << ".\n" << logofs_flush; - - #endif -} - -void GetPropertyStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 1, 1); - md5_append(md5_state_, buffer + 4, 20); -} diff --git a/nxcomp/GetProperty.h b/nxcomp/GetProperty.h deleted file mode 100644 index 46727280b..000000000 --- a/nxcomp/GetProperty.h +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef GetProperty_H -#define GetProperty_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define GETPROPERTY_ENABLE_CACHE 1 -#define GETPROPERTY_ENABLE_DATA 0 -#define GETPROPERTY_ENABLE_SPLIT 0 -#define GETPROPERTY_ENABLE_COMPRESS 0 - -#define GETPROPERTY_DATA_LIMIT 0 -#define GETPROPERTY_DATA_OFFSET 24 - -#define GETPROPERTY_CACHE_SLOTS 2000 -#define GETPROPERTY_CACHE_THRESHOLD 2 -#define GETPROPERTY_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class GetPropertyMessage : public Message -{ - friend class GetPropertyStore; - - public: - - GetPropertyMessage() - { - } - - ~GetPropertyMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char property_delete; - unsigned long window; - unsigned long property; - unsigned long type; - unsigned long long_offset; - unsigned long long_length; -}; - -class GetPropertyStore : public MessageStore -{ - - // - // Constructors and destructors. - // - - public: - - GetPropertyStore() : MessageStore() - { - enableCache = GETPROPERTY_ENABLE_CACHE; - enableData = GETPROPERTY_ENABLE_DATA; - enableSplit = GETPROPERTY_ENABLE_SPLIT; - enableCompress = GETPROPERTY_ENABLE_COMPRESS; - - dataLimit = GETPROPERTY_DATA_LIMIT; - dataOffset = GETPROPERTY_DATA_OFFSET; - - cacheSlots = GETPROPERTY_CACHE_SLOTS; - cacheThreshold = GETPROPERTY_CACHE_THRESHOLD; - cacheLowerThreshold = GETPROPERTY_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~GetPropertyStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "GetProperty"; - } - - virtual unsigned char opcode() const - { - return X_GetProperty; - } - - virtual unsigned int storage() const - { - return sizeof(GetPropertyMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new GetPropertyMessage(); - } - - virtual Message *create(const Message &message) const - { - return new GetPropertyMessage((const GetPropertyMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (GetPropertyMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* GetProperty_H */ diff --git a/nxcomp/GetPropertyReply.cpp b/nxcomp/GetPropertyReply.cpp deleted file mode 100644 index 2d0657a4a..000000000 --- a/nxcomp/GetPropertyReply.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "GetPropertyReply.h" - -#include "ServerCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -GetPropertyReplyStore::GetPropertyReplyStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = GETPROPERTYREPLY_ENABLE_CACHE; - enableData = GETPROPERTYREPLY_ENABLE_DATA; - enableSplit = GETPROPERTYREPLY_ENABLE_SPLIT; - - // Since ProtoStep7 (#issue 108) - enableCompress = GETPROPERTYREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = GETPROPERTYREPLY_DATA_LIMIT; - dataOffset = GETPROPERTYREPLY_DATA_OFFSET; - - cacheSlots = GETPROPERTYREPLY_CACHE_SLOTS; - cacheThreshold = GETPROPERTYREPLY_CACHE_THRESHOLD; - cacheLowerThreshold = GETPROPERTYREPLY_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -GetPropertyReplyStore::~GetPropertyReplyStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int GetPropertyReplyStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ServerCache *serverCache = (ServerCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message identity.\n" - << logofs_flush; - #endif - - unsigned char format = (unsigned int) *(buffer + 1); - - encodeBuffer.encodeCachedValue(format, 8, - serverCache -> getPropertyFormatCache); - - unsigned int numBytes = GetULONG(buffer + 16, bigEndian); - - encodeBuffer.encodeValue(numBytes, 32, 9); - - if (format == 16) - { - numBytes <<= 1; - } - else if (format == 32) - { - numBytes <<= 2; - } - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 8, bigEndian), 29, - serverCache -> getPropertyTypeCache, 9); - - encodeBuffer.encodeValue(GetULONG(buffer + 12, bigEndian), 32, 9); - - #ifdef DEBUG - *logofs << name() << ": Encoded full message identity.\n" - << logofs_flush; - #endif - - return 1; -} - -int GetPropertyReplyStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ServerCache *serverCache = (ServerCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message identity.\n" - << logofs_flush; - #endif - - unsigned char format; - - decodeBuffer.decodeCachedValue(format, 8, - serverCache -> getPropertyFormatCache); - - unsigned int length; - - decodeBuffer.decodeValue(length, 32, 9); - - unsigned int numBytes = length; - - if (format == 16) - { - numBytes <<= 1; - } - else if (format == 32) - { - numBytes <<= 2; - } - - size = 32 + RoundUp4(numBytes); - - buffer = writeBuffer -> addMessage(size); - - *(buffer + 1) = format; - - PutULONG(length, buffer + 16, bigEndian); - - unsigned int value; - - decodeBuffer.decodeCachedValue(value, 29, - serverCache -> getPropertyTypeCache, 9); - - PutULONG(value, buffer + 8, bigEndian); - - decodeBuffer.decodeValue(value, 32, 9); - - PutULONG(value, buffer + 12, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Decoded full message identity.\n" - << logofs_flush; - #endif - - return 1; -} - -int GetPropertyReplyStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GetPropertyReplyMessage *getPropertyReply = (GetPropertyReplyMessage *) message; - - getPropertyReply -> format = *(buffer + 1); - - getPropertyReply -> type = GetULONG(buffer + 8, bigEndian); - getPropertyReply -> after = GetULONG(buffer + 12, bigEndian); - getPropertyReply -> items = GetULONG(buffer + 16, bigEndian); - - // - // Cleanup the padding bytes. - // - - unsigned int uiLengthInBytes; - unsigned int uiFormat; - - if ((int) size > GETPROPERTYREPLY_DATA_OFFSET) - { - uiLengthInBytes = getPropertyReply -> items; - - uiFormat = *(buffer + 1); - - #ifdef DEBUG - *logofs << name() << ": length " << uiLengthInBytes - << ", format " << uiFormat << ", size " - << size << ".\n" << logofs_flush; - #endif - - if (uiFormat == 16) - { - uiLengthInBytes <<= 1; - } - else if (uiFormat == 32) - { - uiLengthInBytes <<= 2; - } - - unsigned char *end = ((unsigned char *) buffer) + size; - unsigned char *pad = ((unsigned char *) buffer) + GETPROPERTYREPLY_DATA_OFFSET + uiLengthInBytes; - - CleanData((unsigned char *) pad, end - pad); - } - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int GetPropertyReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - GetPropertyReplyMessage *getPropertyReply = (GetPropertyReplyMessage *) message; - - *(buffer + 1) = getPropertyReply -> format; - - PutULONG(getPropertyReply -> type, buffer + 8, bigEndian); - PutULONG(getPropertyReply -> after, buffer + 12, bigEndian); - PutULONG(getPropertyReply -> items, buffer + 16, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void GetPropertyReplyStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - GetPropertyReplyMessage *getPropertyReply = (GetPropertyReplyMessage *) message; - - *logofs << name() << ": Identity format " - << (unsigned) getPropertyReply -> format << ", type " - << getPropertyReply -> type << ", after " << getPropertyReply -> after - << ", items " << getPropertyReply -> items << ", size " - << getPropertyReply -> size_ << ".\n"; - - #endif -} - -void GetPropertyReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Fields format, type, after, items. - // - - md5_append(md5_state_, buffer + 1, 1); - md5_append(md5_state_, buffer + 8, 12); -} - -void GetPropertyReplyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ -} - -void GetPropertyReplyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ -} diff --git a/nxcomp/GetPropertyReply.h b/nxcomp/GetPropertyReply.h deleted file mode 100644 index 01634b408..000000000 --- a/nxcomp/GetPropertyReply.h +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef GetPropertyReply_H -#define GetPropertyReply_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define GETPROPERTYREPLY_ENABLE_CACHE 1 -#define GETPROPERTYREPLY_ENABLE_DATA 1 -#define GETPROPERTYREPLY_ENABLE_SPLIT 0 - -#define GETPROPERTYREPLY_DATA_LIMIT 1048576 - 32 -#define GETPROPERTYREPLY_DATA_OFFSET 32 - -#define GETPROPERTYREPLY_CACHE_SLOTS 400 -#define GETPROPERTYREPLY_CACHE_THRESHOLD 5 -#define GETPROPERTYREPLY_CACHE_LOWER_THRESHOLD 1 - -#define GETPROPERTYREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -// -// The message class. -// - -class GetPropertyReplyMessage : public Message -{ - friend class GetPropertyReplyStore; - - public: - - GetPropertyReplyMessage() - { - } - - ~GetPropertyReplyMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char format; - unsigned int type; - unsigned int after; - unsigned int items; -}; - -class GetPropertyReplyStore : public MessageStore -{ - public: - - GetPropertyReplyStore(StaticCompressor *compressor); - - virtual ~GetPropertyReplyStore(); - - virtual const char *name() const - { - return "GetPropertyReply"; - } - - virtual unsigned char opcode() const - { - return X_GetProperty; - } - - virtual unsigned int storage() const - { - return sizeof(GetPropertyReplyMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new GetPropertyReplyMessage(); - } - - virtual Message *create(const Message &message) const - { - return new GetPropertyReplyMessage((const GetPropertyReplyMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (GetPropertyReplyMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* GetPropertyReply_H */ diff --git a/nxcomp/ImageText16.cpp b/nxcomp/ImageText16.cpp deleted file mode 100644 index f3315d4ba..000000000 --- a/nxcomp/ImageText16.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ImageText16.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int ImageText16Store::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ImageText16Message *imageText16 = (ImageText16Message *) message; - - // - // Here is the fingerprint. - // - - imageText16 -> len = *(buffer + 1); - - imageText16 -> drawable = GetULONG(buffer + 4, bigEndian); - imageText16 -> gcontext = GetULONG(buffer + 8, bigEndian); - - imageText16 -> x = GetUINT(buffer + 12, bigEndian); - imageText16 -> y = GetUINT(buffer + 14, bigEndian); - - if ((int) size > dataOffset) - { - int pad = (size - dataOffset) - (imageText16 -> len * 2); - - if (pad > 0) - { - CleanData((unsigned char *) buffer + size - pad, pad); - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int ImageText16Store::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ImageText16Message *imageText16 = (ImageText16Message *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = imageText16 -> len; - - PutULONG(imageText16 -> drawable, buffer + 4, bigEndian); - PutULONG(imageText16 -> gcontext, buffer + 8, bigEndian); - - PutUINT(imageText16 -> x, buffer + 12, bigEndian); - PutUINT(imageText16 -> y, buffer + 14, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void ImageText16Store::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - ImageText16Message *imageText16 = (ImageText16Message *) message; - - *logofs << name() << ": Identity len " << (unsigned int) imageText16 -> len - << " drawable " << imageText16 -> drawable << ", gcontext " - << imageText16 -> gcontext << ", x " << imageText16 -> x << ", y " - << imageText16 -> y << ", size " << imageText16 -> size_ << ".\n"; - - #endif -} - -void ImageText16Store::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 1, 1); -} - -void ImageText16Store::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - ImageText16Message *imageText16 = (ImageText16Message *) message; - ImageText16Message *cachedImageText16 = (ImageText16Message *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << imageText16 -> drawable - << " as " << "drawable" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(imageText16 -> drawable, clientCache -> drawableCache); - - cachedImageText16 -> drawable = imageText16 -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << imageText16 -> gcontext - << " as " << "gcontext" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(imageText16 -> gcontext, clientCache -> gcCache); - - cachedImageText16 -> gcontext = imageText16 -> gcontext; - - #ifdef TEST - *logofs << name() << ": Encoding value " << imageText16 -> x - << " as " << "x" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_x = imageText16 -> x - cachedImageText16 -> x; - - encodeBuffer.encodeCachedValue(diff_x, 16, - clientCache -> imageTextCacheX); - - cachedImageText16 -> x = imageText16 -> x; - - #ifdef TEST - *logofs << name() << ": Encoding value " << imageText16 -> y - << " as " << "y" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_y = imageText16 -> y - cachedImageText16 -> y; - - encodeBuffer.encodeCachedValue(diff_y, 16, - clientCache -> imageTextCacheY); - - cachedImageText16 -> y = imageText16 -> y; -} - -void ImageText16Store::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - ImageText16Message *imageText16 = (ImageText16Message *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - imageText16 -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << imageText16 -> drawable - << " as " << "drawable" << " field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - imageText16 -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << imageText16 -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> imageTextCacheX); - - imageText16 -> x += value; - imageText16 -> x &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << imageText16 -> x - << " as x field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> imageTextCacheY); - - imageText16 -> y += value; - imageText16 -> y &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << imageText16 -> y - << " as y field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/ImageText16.h b/nxcomp/ImageText16.h deleted file mode 100644 index 98462ab35..000000000 --- a/nxcomp/ImageText16.h +++ /dev/null @@ -1,190 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ImageText16_H -#define ImageText16_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define IMAGETEXT16_ENABLE_CACHE 1 -#define IMAGETEXT16_ENABLE_DATA 0 -#define IMAGETEXT16_ENABLE_SPLIT 0 -#define IMAGETEXT16_ENABLE_COMPRESS 0 - -#define IMAGETEXT16_DATA_LIMIT 512 -#define IMAGETEXT16_DATA_OFFSET 16 - -#define IMAGETEXT16_CACHE_SLOTS 3000 -#define IMAGETEXT16_CACHE_THRESHOLD 5 -#define IMAGETEXT16_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class ImageText16Message : public Message -{ - friend class ImageText16Store; - - public: - - ImageText16Message() - { - } - - ~ImageText16Message() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char len; - - unsigned int drawable; - unsigned int gcontext; - - unsigned short x; - unsigned short y; -}; - -class ImageText16Store : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - ImageText16Store() : MessageStore() - { - enableCache = IMAGETEXT16_ENABLE_CACHE; - enableData = IMAGETEXT16_ENABLE_DATA; - enableSplit = IMAGETEXT16_ENABLE_SPLIT; - enableCompress = IMAGETEXT16_ENABLE_COMPRESS; - - dataLimit = IMAGETEXT16_DATA_LIMIT; - dataOffset = IMAGETEXT16_DATA_OFFSET; - - cacheSlots = IMAGETEXT16_CACHE_SLOTS; - cacheThreshold = IMAGETEXT16_CACHE_THRESHOLD; - cacheLowerThreshold = IMAGETEXT16_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~ImageText16Store() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "ImageText16"; - } - - virtual unsigned char opcode() const - { - return X_ImageText16; - } - - virtual unsigned int storage() const - { - return sizeof(ImageText16Message); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new ImageText16Message(); - } - - virtual Message *create(const Message &message) const - { - return new ImageText16Message((const ImageText16Message &) message); - } - - virtual void destroy(Message *message) const - { - delete (ImageText16Message *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* ImageText16_H */ diff --git a/nxcomp/ImageText8.cpp b/nxcomp/ImageText8.cpp deleted file mode 100644 index b0d6ac44e..000000000 --- a/nxcomp/ImageText8.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ImageText8.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int ImageText8Store::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ImageText8Message *imageText8 = (ImageText8Message *) message; - - // - // Here is the fingerprint. - // - - imageText8 -> len = *(buffer + 1); - - imageText8 -> drawable = GetULONG(buffer + 4, bigEndian); - imageText8 -> gcontext = GetULONG(buffer + 8, bigEndian); - - imageText8 -> x = GetUINT(buffer + 12, bigEndian); - imageText8 -> y = GetUINT(buffer + 14, bigEndian); - - if ((int) size > dataOffset) - { - int pad = (size - dataOffset) - imageText8 -> len; - - if (pad > 0) - { - CleanData((unsigned char *) buffer + size - pad, pad); - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int ImageText8Store::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ImageText8Message *imageText8 = (ImageText8Message *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = imageText8 -> len; - - PutULONG(imageText8 -> drawable, buffer + 4, bigEndian); - PutULONG(imageText8 -> gcontext, buffer + 8, bigEndian); - - PutUINT(imageText8 -> x, buffer + 12, bigEndian); - PutUINT(imageText8 -> y, buffer + 14, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void ImageText8Store::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - ImageText8Message *imageText8 = (ImageText8Message *) message; - - *logofs << name() << ": Identity len " << (unsigned int) imageText8 -> len - << " drawable " << imageText8 -> drawable << ", gcontext " - << imageText8 -> gcontext << ", x " << imageText8 -> x << ", y " - << imageText8 -> y << ", size " << imageText8 -> size_ << ".\n"; - - #endif -} - -void ImageText8Store::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 1, 1); -} - -void ImageText8Store::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - ImageText8Message *imageText8 = (ImageText8Message *) message; - ImageText8Message *cachedImageText8 = (ImageText8Message *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << imageText8 -> drawable - << " as " << "drawable" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(imageText8 -> drawable, clientCache -> drawableCache); - - cachedImageText8 -> drawable = imageText8 -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << imageText8 -> gcontext - << " as " << "gcontext" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(imageText8 -> gcontext, clientCache -> gcCache); - - cachedImageText8 -> gcontext = imageText8 -> gcontext; - - #ifdef TEST - *logofs << name() << ": Encoding value " << imageText8 -> x - << " as " << "x" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_x = imageText8 -> x - cachedImageText8 -> x; - - encodeBuffer.encodeCachedValue(diff_x, 16, - clientCache -> imageTextCacheX); - - cachedImageText8 -> x = imageText8 -> x; - - #ifdef TEST - *logofs << name() << ": Encoding value " << imageText8 -> y - << " as " << "y" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_y = imageText8 -> y - cachedImageText8 -> y; - - encodeBuffer.encodeCachedValue(diff_y, 16, - clientCache -> imageTextCacheY); - - cachedImageText8 -> y = imageText8 -> y; -} - -void ImageText8Store::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - ImageText8Message *imageText8 = (ImageText8Message *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - imageText8 -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << imageText8 -> drawable - << " as " << "drawable" << " field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - imageText8 -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << imageText8 -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> imageTextCacheX); - - imageText8 -> x += value; - imageText8 -> x &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << imageText8 -> x - << " as x field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> imageTextCacheY); - - imageText8 -> y += value; - imageText8 -> y &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << imageText8 -> y - << " as y field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/ImageText8.h b/nxcomp/ImageText8.h deleted file mode 100644 index aa9ccb5d9..000000000 --- a/nxcomp/ImageText8.h +++ /dev/null @@ -1,190 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ImageText8_H -#define ImageText8_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define IMAGETEXT8_ENABLE_CACHE 1 -#define IMAGETEXT8_ENABLE_DATA 0 -#define IMAGETEXT8_ENABLE_SPLIT 0 -#define IMAGETEXT8_ENABLE_COMPRESS 0 - -#define IMAGETEXT8_DATA_LIMIT 256 -#define IMAGETEXT8_DATA_OFFSET 16 - -#define IMAGETEXT8_CACHE_SLOTS 3000 -#define IMAGETEXT8_CACHE_THRESHOLD 5 -#define IMAGETEXT8_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class ImageText8Message : public Message -{ - friend class ImageText8Store; - - public: - - ImageText8Message() - { - } - - ~ImageText8Message() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char len; - - unsigned int drawable; - unsigned int gcontext; - - unsigned short x; - unsigned short y; -}; - -class ImageText8Store : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - ImageText8Store() : MessageStore() - { - enableCache = IMAGETEXT8_ENABLE_CACHE; - enableData = IMAGETEXT8_ENABLE_DATA; - enableSplit = IMAGETEXT8_ENABLE_SPLIT; - enableCompress = IMAGETEXT8_ENABLE_COMPRESS; - - dataLimit = IMAGETEXT8_DATA_LIMIT; - dataOffset = IMAGETEXT8_DATA_OFFSET; - - cacheSlots = IMAGETEXT8_CACHE_SLOTS; - cacheThreshold = IMAGETEXT8_CACHE_THRESHOLD; - cacheLowerThreshold = IMAGETEXT8_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~ImageText8Store() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "ImageText8"; - } - - virtual unsigned char opcode() const - { - return X_ImageText8; - } - - virtual unsigned int storage() const - { - return sizeof(ImageText8Message); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new ImageText8Message(); - } - - virtual Message *create(const Message &message) const - { - return new ImageText8Message((const ImageText8Message &) message); - } - - virtual void destroy(Message *message) const - { - delete (ImageText8Message *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* ImageText8_H */ diff --git a/nxcomp/IntCache.cpp b/nxcomp/IntCache.cpp deleted file mode 100644 index 362412182..000000000 --- a/nxcomp/IntCache.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include - -#include "Misc.h" -#include "IntCache.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -IntCache::IntCache(unsigned int size) - - : size_(size), length_(0), buffer_(new unsigned int[size]), - lastDiff_(0), lastValueInserted_(0), predictedBlockSize_(0) -{ -} - -int IntCache::lookup(unsigned int &value, unsigned int &index, - unsigned int mask, unsigned int &sameDiff) -{ - for (unsigned int i = 0; i < length_; i++) - { - if (value == buffer_[i]) - { - index = i; - if (i) - { - unsigned int target = (i >> 1); - do - { - buffer_[i] = buffer_[i - 1]; - i--; - } - while (i > target); - buffer_[target] = value; - } - return 1; - } - } - unsigned int insertionPoint; - if (2 >= length_) - insertionPoint = length_; - else - insertionPoint = 2; - unsigned int start; - if (length_ >= size_) - start = size_ - 1; - else - { - start = length_; - length_++; - } - for (unsigned int k = start; k > insertionPoint; k--) - buffer_[k] = buffer_[k - 1]; - buffer_[insertionPoint] = value; - unsigned int diff = value - lastValueInserted_; - - lastValueInserted_ = (value & mask); - value = (diff & mask); - sameDiff = (value == lastDiff_); - if (!sameDiff) - { - lastDiff_ = value; - - unsigned int lastChangeIndex = 0; - unsigned int lastBitIsOne = (lastDiff_ & 0x1); - unsigned int j = 1; - for (unsigned int nextMask = 0x2; nextMask & mask; nextMask <<= 1) - { - unsigned int nextBitIsOne = (lastDiff_ & nextMask); - if (nextBitIsOne) - { - if (!lastBitIsOne) - { - lastChangeIndex = j; - lastBitIsOne = nextBitIsOne; - } - } - else - { - if (lastBitIsOne) - { - lastChangeIndex = j; - lastBitIsOne = nextBitIsOne; - } - } - j++; - } - predictedBlockSize_ = lastChangeIndex + 1; - if (predictedBlockSize_ < 2) - predictedBlockSize_ = 2; - } - return 0; -} - -void IntCache::insert(unsigned int &value, unsigned int mask) -{ - unsigned int insertionPoint; - if (2 >= length_) - insertionPoint = length_; - else - insertionPoint = 2; - unsigned int start; - if (length_ >= size_) - start = size_ - 1; - else - { - start = length_; - length_++; - } - for (unsigned int k = start; k > insertionPoint; k--) - buffer_[k] = buffer_[k - 1]; - if (lastDiff_ != value) - { - lastDiff_ = value; - unsigned int lastChangeIndex = 0; - unsigned int lastBitIsOne = (lastDiff_ & 0x1); - unsigned int j = 1; - for (unsigned int nextMask = 0x2; nextMask & mask; nextMask <<= 1) - { - unsigned int nextBitIsOne = (lastDiff_ & nextMask); - if (nextBitIsOne) - { - if (!lastBitIsOne) - { - lastChangeIndex = j; - lastBitIsOne = nextBitIsOne; - } - } - else - { - if (lastBitIsOne) - { - lastChangeIndex = j; - lastBitIsOne = nextBitIsOne; - } - } - j++; - } - predictedBlockSize_ = lastChangeIndex + 1; - if (predictedBlockSize_ < 2) - predictedBlockSize_ = 2; - } - lastValueInserted_ += value; - lastValueInserted_ &= mask; - buffer_[insertionPoint] = lastValueInserted_; - value = lastValueInserted_; -} - -void IntCache::push(unsigned int &value, unsigned int mask) -{ - // - // Using a memmove() appears to be slower. - // - // memmove((char *) &buffer_[1], (char *) &buffer_[0], - // sizeof(unsigned int) * (size_ - 1)); - // - // if (length_ < size_) - // { - // length_++; - // } - // - - unsigned int start; - - if (length_ >= size_) - { - start = size_ - 1; - } - else - { - start = length_; - - length_++; - } - - for (unsigned int k = start; k > 0; k--) - { - buffer_[k] = buffer_[k - 1]; - } - - value &= mask; - - buffer_[0] = value; -} - -void IntCache::dump() -{ - #ifdef DUMP - - *logofs << "IntCache: Dumping content of cache at " - << (void *) this << ":\n" << logofs_flush; - - for (unsigned int i = 0; i < length_; i++) - { - *logofs << "IntCache: [" << i << "][" << buffer_[i] << "]\n"; - } - - #endif -} diff --git a/nxcomp/IntCache.h b/nxcomp/IntCache.h deleted file mode 100644 index 69c522325..000000000 --- a/nxcomp/IntCache.h +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef IntCache_H -#define IntCache_H - -class IntCache -{ - public: - - IntCache(unsigned int size); - - ~IntCache() - { - delete [] buffer_; - } - - unsigned int getSize() const - { - return length_; - } - - int lookup(unsigned int &value, unsigned int &index, - unsigned int mask, unsigned int &sameDiff); - - // - // This can be inlined as it is only - // called by decodeCachedValue(). - // - - unsigned int get(unsigned int index) - { - unsigned int result = buffer_[index]; - - if (index != 0) - { - // - // Using a memmove() appears to be slower. - // - // unsigned int target = index >> 1; - // - // memmove((char *) &buffer_[target + 1], (char *) &buffer_[target], - // sizeof(unsigned int) * (index - target)); - // - // buffer_[target] = result; - // - - unsigned int i = index; - - unsigned int target = (i >> 1); - - do - { - buffer_[i] = buffer_[i - 1]; - - i--; - } - while (i > target); - - buffer_[target] = result; - } - - return result; - } - - void insert(unsigned int &value, unsigned int mask); - - void push(unsigned int &value, unsigned int mask); - - void dump(); - - unsigned int getLastDiff(unsigned int mask) const - { - return lastDiff_; - } - - unsigned int getBlockSize(unsigned int bits) const - { - if (bits > 0) - { - return (predictedBlockSize_ < bits ? predictedBlockSize_ : bits); - } - - return predictedBlockSize_; - } - - private: - - unsigned int size_; - unsigned int length_; - unsigned int *buffer_; - unsigned int lastDiff_; - unsigned int lastValueInserted_; - unsigned int predictedBlockSize_; -}; - -#endif /* IntCache_H */ diff --git a/nxcomp/InternAtom.cpp b/nxcomp/InternAtom.cpp deleted file mode 100644 index 760d72222..000000000 --- a/nxcomp/InternAtom.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "InternAtom.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int InternAtomStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - InternAtomMessage *internAtom = (InternAtomMessage *) message; - - // - // Here is the fingerprint. - // - - internAtom -> only_if_exists = *(buffer + 1); - internAtom -> name_length = GetUINT(buffer + 4, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - // - // Clean up padding bytes. - // - - if ((int) size > dataOffset) - { - unsigned char *end = ((unsigned char *) buffer) + size; - - for (unsigned char *pad = ((unsigned char *) buffer) + 8 + - internAtom -> name_length; pad < end; pad++) - { - *pad = 0; - } - } - - return 1; -} - -int InternAtomStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - InternAtomMessage *internAtom = (InternAtomMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = internAtom -> only_if_exists; - - PutUINT(internAtom -> name_length, buffer + 4, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void InternAtomStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - InternAtomMessage *internAtom = (InternAtomMessage *) message; - - *logofs << name() << ": Identity only_if_exists " - << (unsigned int) internAtom -> only_if_exists - << ", name_length " << internAtom -> name_length - << ", name '"; - - for (int i = 0; i < internAtom -> name_length; i++) - { - *logofs << internAtom -> data_[i]; - } - - *logofs << "'.\n" << logofs_flush; - - #endif -} - -void InternAtomStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 1, 1); - md5_append(md5_state_, buffer + 4, 2); -} diff --git a/nxcomp/InternAtom.h b/nxcomp/InternAtom.h deleted file mode 100644 index 6e69eca24..000000000 --- a/nxcomp/InternAtom.h +++ /dev/null @@ -1,178 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef InternAtom_H -#define InternAtom_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define INTERNATOM_ENABLE_CACHE 1 -#define INTERNATOM_ENABLE_DATA 0 -#define INTERNATOM_ENABLE_SPLIT 0 -#define INTERNATOM_ENABLE_COMPRESS 0 - -#define INTERNATOM_DATA_LIMIT 80 -#define INTERNATOM_DATA_OFFSET 8 - -#define INTERNATOM_CACHE_SLOTS 2000 -#define INTERNATOM_CACHE_THRESHOLD 2 -#define INTERNATOM_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class InternAtomMessage : public Message -{ - friend class InternAtomStore; - - public: - - InternAtomMessage() - { - } - - ~InternAtomMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char only_if_exists; - unsigned short name_length; -}; - -class InternAtomStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - InternAtomStore() : MessageStore() - { - enableCache = INTERNATOM_ENABLE_CACHE; - enableData = INTERNATOM_ENABLE_DATA; - enableSplit = INTERNATOM_ENABLE_SPLIT; - enableCompress = INTERNATOM_ENABLE_COMPRESS; - - dataLimit = INTERNATOM_DATA_LIMIT; - dataOffset = INTERNATOM_DATA_OFFSET; - - cacheSlots = INTERNATOM_CACHE_SLOTS; - cacheThreshold = INTERNATOM_CACHE_THRESHOLD; - cacheLowerThreshold = INTERNATOM_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~InternAtomStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "InternAtom"; - } - - virtual unsigned char opcode() const - { - return X_InternAtom; - } - - virtual unsigned int storage() const - { - return sizeof(InternAtomMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new InternAtomMessage(); - } - - virtual Message *create(const Message &message) const - { - return new InternAtomMessage((const InternAtomMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (InternAtomMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* InternAtom_H */ diff --git a/nxcomp/Jpeg.cpp b/nxcomp/Jpeg.cpp deleted file mode 100644 index 54fa71d21..000000000 --- a/nxcomp/Jpeg.cpp +++ /dev/null @@ -1,886 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include - -#ifdef ANDROID -#include -#endif -#include -#include -#include - -#ifdef __cplusplus - -extern "C" -{ - #include - #include -} - -#else - -#include -#include - -#endif - -#include "Misc.h" -#include "Jpeg.h" -#include "Unpack.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#define RGB24_TO_PIXEL(bpp,r,g,b) \ - ((((CARD##bpp)(r) & 0xff) * srcRedMax + 127) / 255 \ - << srcRedShift | \ - (((CARD##bpp)(g) & 0xff) * srcGreenMax + 127) / 255 \ - << srcGreenShift | \ - (((CARD##bpp)(b) & 0xff) * srcBlueMax + 127) / 255 \ - << srcBlueShift) - -#define RGB24_TO_PIXEL32(r,g,b) \ - (((CARD32)(r) & 0xff) << srcRedShift | \ - ((CARD32)(g) & 0xff) << srcGreenShift | \ - ((CARD32)(b) & 0xff) << srcBlueShift) - -// -// Functions from Unpack.cpp -// - -extern int Unpack32To32(const T_colormask *colormask, const unsigned int *data, - unsigned int *out, unsigned int *end); - -extern int Unpack24To24(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -extern int Unpack16To16(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -// -// Local functions used for the jpeg decompression. -// - -static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData, int compressedLen); -static void JpegInitSource(j_decompress_ptr cinfo); -static void JpegTermSource(j_decompress_ptr cinfo); -static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes); - -static boolean JpegFillInputBuffer(j_decompress_ptr cinfo); - -static int DecompressJpeg16(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder); - -static int DecompressJpeg24(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder); - -static int DecompressJpeg32(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder); - -void UnpackJpegErrorHandler(j_common_ptr cinfo); - -// -// Colormap stuff. -// - -CARD16 srcRedMax, srcGreenMax, srcBlueMax; -CARD8 srcRedShift, srcGreenShift, srcBlueShift; - -// -// Error handler. -// - -static bool jpegError; - -jmp_buf UnpackJpegContext; - -void UnpackJpegErrorHandler(j_common_ptr cinfo) -{ - #ifdef PANIC - *logofs << "UnpackJpegErrorHandler: PANIC! Detected error in JPEG decompression.\n" - << logofs_flush; - - *logofs << "UnpackJpegErrorHandler: PANIC! Trying to revert to the previous context.\n" - << logofs_flush; - #endif - - jpegError = 1; - - longjmp(UnpackJpegContext, 1); -} - -// -// Attributes used for the jpeg decompression. -// - -static struct jpeg_source_mgr jpegSrcManager; -static JOCTET *jpegBufferPtr; -static size_t jpegBufferLen; - -static char *tmpBuf; -static int tmpBufSize = 0; - -int UnpackJpeg(T_geometry *geometry, unsigned char method, unsigned char *srcData, - int srcSize, int dstBpp, int dstWidth, int dstHeight, - unsigned char *dstData, int dstSize) -{ - int byteOrder = geometry -> image_byte_order; - - // - // Check if data is coming from a failed unsplit. - // - - if (srcSize < 2 || (srcData[0] == SPLIT_PATTERN && - srcData[1] == SPLIT_PATTERN)) - { - #ifdef WARNING - *logofs << "UnpackJpeg: WARNING! Skipping unpack of dummy data.\n" - << logofs_flush; - #endif - - return -1; - } - - #ifdef DEBUG - *logofs << "UnpackJpeg: Decompression. Source size " - << srcSize << " bits per plane " << dstBpp - << ".\n" << logofs_flush; - #endif - - srcRedShift = ffs(geometry -> red_mask) - 1; - srcGreenShift = ffs(geometry -> green_mask) - 1; - srcBlueShift = ffs(geometry -> blue_mask) - 1; - - #ifdef DEBUG - *logofs << "UnpackJpeg: Red shift " << (int) srcRedShift - << " green shift " << (int) srcGreenShift << " blue shift " - << (int) srcBlueShift << ".\n" << logofs_flush; - #endif - - srcRedMax = geometry -> red_mask >> srcRedShift; - srcGreenMax = geometry -> green_mask >> srcGreenShift; - srcBlueMax = geometry -> blue_mask >> srcBlueShift; - - #ifdef DEBUG - *logofs << "UnpackJpeg: Red mask " << (void *) geometry -> red_mask - << " green mask " << (void *) geometry -> green_mask - << " blue mask " << (void *) geometry -> blue_mask - << ".\n" << logofs_flush; - #endif - - #ifdef DEBUG - *logofs << "UnpackJpeg: Red max " << srcRedMax << " green max " - << srcGreenMax << " blue max " << srcBlueMax - << ".\n" << logofs_flush; - #endif - - // - // Make enough space in the temporary - // buffer to have one complete row of - // the image with 3 bytes for a pixel. - // - - tmpBufSize = dstWidth * 3; - tmpBuf = new char[tmpBufSize]; - - if (tmpBuf == NULL) - { - #ifdef PANIC - *logofs << "UnpackJpeg: PANIC! Cannot allocate " - << dstWidth * 3 << " bytes for Jpeg " - << "decompressed data.\n" << logofs_flush; - #endif - - delete [] tmpBuf; - - return -1; - } - - int result = 1; - - switch(dstBpp) - { - case 8: - { - // - // Simply move the data from srcData to dstData - // taking into consideration the correct padding. - // - - int row; - - unsigned char * dstBuff = dstData; - unsigned char * srcBuff = srcData; - - for (row = 0; row < dstHeight; row++) - { - memcpy(dstBuff, srcBuff, dstWidth); - - dstBuff += RoundUp4(dstWidth); - srcBuff += dstWidth; - } - - break; - } - case 16: - { - result = DecompressJpeg16(srcData, srcSize, dstWidth, - dstHeight, dstData, byteOrder); - break; - } - case 24: - { - result = DecompressJpeg24(srcData, srcSize, dstWidth, - dstHeight, dstData, byteOrder); - break; - } - case 32: - { - result = DecompressJpeg32(srcData, srcSize, dstWidth, - dstHeight, dstData, byteOrder); - break; - } - default: - { - #ifdef PANIC - *logofs << "UnpackJpeg: PANIC! Failed to decode Jpeg image. " - << " Unsupported Bpp value " << dstBpp - << " for the Jpeg compression" - << ".\n" << logofs_flush; - #endif - - delete [] tmpBuf; - - result = -1; - } - } - - #ifdef DEBUG - *logofs << "UnpackJpeg: Decompression finished with result " - << result << ".\n" << logofs_flush; - #endif - - if (result == -1) - { - delete [] tmpBuf; - - #ifdef PANIC - *logofs << "UnpackJpeg: PANIC! Failed to decode Jpeg image using " - << dstBpp << " Bpp destination.\n" << logofs_flush; - #endif - - return result; - } - - // - // Apply the correction for the brightness. - // - - int maskMethod; - - switch(method) - { - case PACK_JPEG_8_COLORS: - { - maskMethod = MASK_8_COLORS; - - break; - } - case PACK_JPEG_64_COLORS: - { - maskMethod = MASK_64_COLORS; - - break; - } - case PACK_JPEG_256_COLORS: - { - maskMethod = MASK_256_COLORS; - - break; - } - case PACK_JPEG_512_COLORS: - { - maskMethod = MASK_512_COLORS; - - break; - } - case PACK_JPEG_4K_COLORS: - { - maskMethod = MASK_4K_COLORS; - - break; - } - case PACK_JPEG_32K_COLORS: - { - maskMethod = MASK_32K_COLORS; - - break; - } - case PACK_JPEG_64K_COLORS: - { - maskMethod = MASK_64K_COLORS; - - break; - } - case PACK_JPEG_256K_COLORS: - { - maskMethod = MASK_256K_COLORS; - - break; - } - case PACK_JPEG_2M_COLORS: - { - maskMethod = MASK_2M_COLORS; - - break; - } - case PACK_JPEG_16M_COLORS: - { - maskMethod = MASK_16M_COLORS; - - break; - } - default: - { - delete [] tmpBuf; - - return -1; - } - } - - const T_colormask *colorMask = MethodColorMask(maskMethod); - - unsigned char *dstBuff = dstData; - - switch (dstBpp) - { - case 16: - { - Unpack16To16(colorMask, dstBuff, dstBuff, dstBuff + dstSize); - - break; - } - case 24: - { - break; - } - case 32: - { - Unpack32To32(colorMask, (unsigned int *) dstBuff, (unsigned int *) dstBuff, - (unsigned int *) (dstBuff + dstSize)); - break; - } - default: - { - delete [] tmpBuf; - - return -1; - } - } - - delete [] tmpBuf; - - return 1; -} - -// -// Functions that actually do the Jpeg decompression. -// - -int DecompressJpeg16(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - unsigned char *data; - JSAMPROW rowPointer[1]; - - unsigned int dx = 0; - unsigned int dy = 0; - - #ifdef DEBUG - *logofs << "DecompressJpeg16: Decompressing with length " - << compressedLen << " width " << w << " height " - << h << ".\n" << logofs_flush; - #endif - - jpegError = 0; - - cinfo.err = jpeg_std_error(&jerr); - - jerr.error_exit = UnpackJpegErrorHandler; - - if (setjmp(UnpackJpegContext) == 1) - { - #ifdef TEST - *logofs << "DecompressJpeg16: Out of the long jump with error '" - << jpegError << "'.\n" << logofs_flush; - #endif - - goto AbortDecompressJpeg16; - } - - jpeg_create_decompress(&cinfo); - - if (jpegError) goto AbortDecompressJpeg16; - - JpegSetSrcManager(&cinfo, compressedData, compressedLen); - - jpeg_read_header(&cinfo, TRUE); - - if (jpegError) goto AbortDecompressJpeg16; - - cinfo.out_color_space = JCS_RGB; - - jpeg_start_decompress(&cinfo); - - if (jpegError) goto AbortDecompressJpeg16; - - if (cinfo.output_width != w || - cinfo.output_height != h || - cinfo.output_components != 3) - { - #ifdef PANIC - *logofs << "DecompressJpeg16: PANIC! Wrong JPEG data received.\n" - << logofs_flush; - #endif - - jpeg_destroy_decompress(&cinfo); - - return -1; - } - - // - // PixelPtr points to dstBuf which is - // already padded correctly for the final - // image to put - // - - data = dstBuf; - - rowPointer[0] = (JSAMPROW) tmpBuf; - - unsigned long pixel; - - while (cinfo.output_scanline < cinfo.output_height) - { - jpeg_read_scanlines(&cinfo, rowPointer, 1); - - if (jpegError) goto AbortDecompressJpeg16; - - for (dx = 0; dx < w; dx++) - { - pixel = RGB24_TO_PIXEL(16, tmpBuf[dx * 3], tmpBuf[dx * 3 + 1], - tmpBuf[dx * 3 + 2]); - - // - // Follow the server byte order when arranging data. - // - - if (byteOrder == LSBFirst) - { - data[0] = (unsigned char) (pixel & 0xff); - data[1] = (unsigned char) ((pixel >> 8) & 0xff); - } - else - { - data[1] = (unsigned char) (pixel & 0xff); - data[0] = (unsigned char) ((pixel >> 8) & 0xff); - } - - data += 2; - } - - // - // Move data at the beginning of the - // next line. - // - - data = data + (RoundUp4(w * 2) - w * 2); - - dy++; - } - - AbortDecompressJpeg16: - - if (jpegError == 0) - { - jpeg_finish_decompress(&cinfo); - } - - jpeg_destroy_decompress(&cinfo); - - if (jpegError == 1) - { - #ifdef PANIC - *logofs << "DecompressJpeg16: Failed to decompress JPEG image.\n" - << logofs_flush; - #endif - - return -1; - } - - #ifdef TEST - *logofs << "DecompressJpeg16: Decompression finished with " - << dy << " lines handled.\n" << logofs_flush; - #endif - - return 1; -} - -int DecompressJpeg24(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - CARD8 *pixelPtr = NULL; - JSAMPROW rowPointer[1]; - - unsigned int dx = 0; - unsigned int dy = 0; - - #ifdef TEST - *logofs << "DecompressJpeg24: Decompressing with length " - << compressedLen << " width " << w << " height " - << h << ".\n" << logofs_flush; - #endif - - jpegError = 0; - - cinfo.err = jpeg_std_error(&jerr); - - jerr.error_exit = UnpackJpegErrorHandler; - - if (setjmp(UnpackJpegContext) == 1) - { - #ifdef TEST - *logofs << "DecompressJpeg24: Out of the long jump with error '" - << jpegError << "'.\n" << logofs_flush; - #endif - - goto AbortDecompressJpeg24; - } - - jpeg_create_decompress(&cinfo); - - if (jpegError) goto AbortDecompressJpeg24; - - JpegSetSrcManager(&cinfo, compressedData, compressedLen); - - jpeg_read_header(&cinfo, TRUE); - - if (jpegError) goto AbortDecompressJpeg24; - - cinfo.out_color_space = JCS_RGB; - - jpeg_start_decompress(&cinfo); - - if (jpegError) goto AbortDecompressJpeg24; - - if (cinfo.output_width != w || - cinfo.output_height != h || - cinfo.output_components != 3) - { - #ifdef PANIC - *logofs << "DecompressJpeg24: PANIC! Wrong JPEG data received.\n" - << logofs_flush; - #endif - - jpeg_destroy_decompress(&cinfo); - - return -1; - } - - // - // PixelPtr points to dstBuf which is - // already padded correctly for the final - // image to put. - // - - pixelPtr = (CARD8 *) dstBuf; - - rowPointer[0] = (JSAMPROW) tmpBuf; - - while (cinfo.output_scanline < cinfo.output_height) - { - jpeg_read_scanlines(&cinfo, rowPointer, 1); - - if (jpegError) goto AbortDecompressJpeg24; - - for (dx = 0; dx < w; dx++) - { - // - // Follow the server byte order when arranging data. - // - - if (byteOrder == LSBFirst) - { - pixelPtr[0] = tmpBuf[dx * 3]; - pixelPtr[1] = tmpBuf[dx * 3 + 1]; - pixelPtr[2] = tmpBuf[dx * 3 + 2]; - } - else - { - pixelPtr[2] = tmpBuf[dx * 3]; - pixelPtr[1] = tmpBuf[dx * 3 + 1]; - pixelPtr[0] = tmpBuf[dx * 3 + 2]; - } - - pixelPtr += 3; - } - - // - // Go to the next line. - // - - pixelPtr = (CARD8 *) (((char *) pixelPtr) + (RoundUp4(w * 3) - w * 3)); - - dy++; - } - - AbortDecompressJpeg24: - - if (jpegError == 0) - { - jpeg_finish_decompress(&cinfo); - } - - jpeg_destroy_decompress(&cinfo); - - if (jpegError == 1) - { - #ifdef PANIC - *logofs << "DecompressJpeg24: Failed to decompress JPEG image.\n" - << logofs_flush; - #endif - - return -1; - } - - #ifdef TEST - *logofs << "DecompressJpeg24: Decompression finished with " - << dy << " lines handled.\n" << logofs_flush; - #endif - - return 1; -} - -int DecompressJpeg32(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - unsigned char *data; - JSAMPROW rowPointer[1]; - - unsigned int dx = 0; - unsigned int dy = 0; - - #ifdef TEST - *logofs << "DecompressJpeg32: Decompressing with length " - << compressedLen << " width " << w << " height " - << h << ".\n" << logofs_flush; - #endif - - jpegError = 0; - - cinfo.err = jpeg_std_error(&jerr); - - jerr.error_exit = UnpackJpegErrorHandler; - - if (setjmp(UnpackJpegContext) == 1) - { - #ifdef TEST - *logofs << "DecompressJpeg32: Out of the long jump with error '" - << jpegError << "'.\n" << logofs_flush; - #endif - - goto AbortDecompressJpeg32; - } - - jpeg_create_decompress(&cinfo); - - if (jpegError) goto AbortDecompressJpeg32; - - JpegSetSrcManager(&cinfo, compressedData, compressedLen); - - jpeg_read_header(&cinfo, TRUE); - - if (jpegError) goto AbortDecompressJpeg32; - - cinfo.out_color_space = JCS_RGB; - - jpeg_start_decompress(&cinfo); - - if (jpegError) goto AbortDecompressJpeg32; - - if (cinfo.output_width != w || - cinfo.output_height != h || - cinfo.output_components != 3) - { - #ifdef PANIC - *logofs << "DecompressJpeg32 : PANIC! Wrong JPEG data received.\n" - << logofs_flush; - #endif - - jpeg_destroy_decompress(&cinfo); - - return -1; - } - - // - // PixelPtr points to dstBuf which is - // already padded correctly for the final - // image to put - // - - data = dstBuf; - - rowPointer[0] = (JSAMPROW) tmpBuf; - - unsigned long pixel; - - int i; - - while (cinfo.output_scanline < cinfo.output_height) - { - jpeg_read_scanlines(&cinfo, rowPointer, 1); - - if (jpegError) goto AbortDecompressJpeg32; - - for (dx = 0; dx < w; dx++) - { - pixel = RGB24_TO_PIXEL(32, tmpBuf[dx * 3], tmpBuf[dx * 3 + 1], - tmpBuf[dx * 3 + 2]); - - // - // Follow the server byte order when arranging data. - // - - if (byteOrder == LSBFirst) - { - for (i = 0; i < 4; i++) - { - data[i] = (unsigned char)(pixel & 0xff); - pixel >>= 8; - } - } - else - { - for (i = 3; i >= 0; i--) - { - data[i] = (unsigned char) (pixel & 0xff); - pixel >>= 8; - } - } - - data += 4; - } - - dy++; - } - - AbortDecompressJpeg32: - - if (jpegError == 0) - { - jpeg_finish_decompress(&cinfo); - } - - jpeg_destroy_decompress(&cinfo); - - if (jpegError == 1) - { - #ifdef PANIC - *logofs << "DecompressJpeg32: Failed to decompress JPEG image.\n" - << logofs_flush; - #endif - - return -1; - } - - #ifdef TEST - *logofs << "DecompressJpeg32: Decompression finished with " - << dy << " lines handled.\n" << logofs_flush; - #endif - - return 1; -} - -static void JpegInitSource(j_decompress_ptr cinfo) -{ - jpegError = 0; -} - -static boolean JpegFillInputBuffer(j_decompress_ptr cinfo) -{ - jpegError = 1; - - jpegSrcManager.bytes_in_buffer = jpegBufferLen; - jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr; - - return TRUE; -} - -static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes) -{ - if (num_bytes < 0 || (unsigned long) num_bytes > jpegSrcManager.bytes_in_buffer) - { - jpegError = 1; - - jpegSrcManager.bytes_in_buffer = jpegBufferLen; - jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr; - } - else - { - jpegSrcManager.next_input_byte += (size_t) num_bytes; - jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes; - } -} - -static void JpegTermSource(j_decompress_ptr cinfo) -{ -} - -static void JpegSetSrcManager(j_decompress_ptr cinfo, - CARD8 *compressedData, - int compressedLen) -{ - jpegBufferPtr = (JOCTET *) compressedData; - jpegBufferLen = (size_t) compressedLen; - - jpegSrcManager.init_source = JpegInitSource; - jpegSrcManager.fill_input_buffer = JpegFillInputBuffer; - jpegSrcManager.skip_input_data = JpegSkipInputData; - jpegSrcManager.resync_to_restart = jpeg_resync_to_restart; - jpegSrcManager.term_source = JpegTermSource; - jpegSrcManager.next_input_byte = jpegBufferPtr; - jpegSrcManager.bytes_in_buffer = jpegBufferLen; - - cinfo->src = &jpegSrcManager; -} diff --git a/nxcomp/Jpeg.h b/nxcomp/Jpeg.h deleted file mode 100644 index 58a5bffef..000000000 --- a/nxcomp/Jpeg.h +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Jpeg_H -#define Jpeg_H - -#include "Misc.h" -#include "Unpack.h" - -int UnpackJpeg(T_geometry *geometry, unsigned char method, unsigned char *srcData, - int srcSize, int dstBpp, int dstWidth, int dstHeight, - unsigned char *dstData, int dstSize); - -#endif /* Jpeg_H */ diff --git a/nxcomp/Keeper.cpp b/nxcomp/Keeper.cpp deleted file mode 100644 index 7e8cd0cd7..000000000 --- a/nxcomp/Keeper.cpp +++ /dev/null @@ -1,608 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include -#include - -#include "Keeper.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Remove the directory if it's empty -// since more than 30 * 24 h. -// - -#define EMPTY_DIR_TIME 2592000 - -// -// Sleep once any ONCE entries. -// - -#define ONCE 2 - -// -// Define this to trace messages while -// they are allocated and deallocated. -// - -#undef REFERENCES - -// -// This is used for reference count. -// - -#ifdef REFERENCES - -int File::references_ = 0; - -#endif - -bool T_older::operator () (File *a, File *b) const -{ - return a -> compare(b); -} - -File::File() -{ - name_ = NULL; - - size_ = 0; - time_ = 0; - - #ifdef REFERENCES - - references_++; - - *logofs << "Keeper: Created new File at " - << this << " out of " << references_ - << " allocated references.\n" - << logofs_flush; - - #endif -} - -// -// TODO: This class can leak industrial amounts of memory. -// I'm 100% sure that the desctructor is called and that -// also the string pointed in the File structure is dele- -// ted. Everything is logged, but still the memory is not -// freed. This is less a problem on Windows, where the me- -// mory occupation remains almost constant. Obviously the -// problem lies in the STL allocators of the GNU libstc++. -// - -File::~File() -{ - #ifdef TEST - *logofs << "Keeper: Deleting name for File at " - << this << ".\n" << logofs_flush; - #endif - - delete [] name_; - - #ifdef REFERENCES - - *logofs << "Keeper: Deleted File at " - << this << " out of " << references_ - << " allocated references.\n" - << logofs_flush; - - references_--; - - #endif -} - -bool File::compare(File *b) const -{ - if (this -> time_ == b -> time_) - { - return (this -> size_ < b -> size_); - } - - return (this -> time_ < b -> time_); -} - -Keeper::Keeper(int caches, int images, const char *root, - int sleep, int parent) -{ - caches_ = caches; - images_ = images; - sleep_ = sleep; - parent_ = parent; - - root_ = new char[strlen(root) + 1]; - - strcpy(root_, root); - - total_ = 0; - signal_ = 0; - - files_ = new T_files; -} - -Keeper::~Keeper() -{ - empty(); - - delete files_; - - delete [] root_; -} - -int Keeper::cleanupCaches() -{ - #ifdef TEST - *logofs << "Keeper: Looking for cache directories in '" - << root_ << "'.\n" << logofs_flush; - #endif - - DIR *rootDir = opendir(root_); - - if (rootDir != NULL) - { - dirent *dirEntry; - - struct stat fileStat; - - int baseSize = strlen(root_); - - int s = 0; - - while (((dirEntry = readdir(rootDir)) != NULL)) - { - if (s++ % ONCE == 0) usleep(sleep_ * 1000); - - if (signal_ != 0) break; - - if (strcmp(dirEntry -> d_name, "cache") == 0 || - strncmp(dirEntry -> d_name, "cache-", 6) == 0) - { - char *dirName = new char[baseSize + strlen(dirEntry -> d_name) + 2]; - - if (dirName == NULL) - { - #ifdef WARNING - *logofs << "Keeper: WARNING! Can't check directory entry '" - << dirEntry -> d_name << "'.\n" << logofs_flush; - #endif - - delete [] dirName; - - continue; - } - - strcpy(dirName, root_); - strcpy(dirName + baseSize, "/"); - strcpy(dirName + baseSize + 1, dirEntry -> d_name); - - #ifdef TEST - *logofs << "Keeper: Checking directory '" << dirName - << "'.\n" << logofs_flush; - #endif - - if (stat(dirName, &fileStat) == 0 && - S_ISDIR(fileStat.st_mode) != 0) - { - // - // Add to repository all the "C-" and - // "S-" files in the given directory. - // - - collect(dirName); - } - - delete [] dirName; - } - } - - closedir(rootDir); - } - else - { - #ifdef WARNING - *logofs << "Keeper: WARNING! Can't open NX root directory '" - << root_ << "'. Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Can't open NX root directory '" - << root_ << "'. Error is " << EGET() << " '" - << ESTR() << "'.\n"; - } - - // - // Remove older files. - // - - cleanup(caches_); - - // - // Empty the repository. - // - - empty(); - - return 1; -} - -int Keeper::cleanupImages() -{ - #ifdef TEST - *logofs << "Keeper: Looking for image directory in '" - << root_ << "'.\n" << logofs_flush; - #endif - - char *imagesPath = new char[strlen(root_) + strlen("/images") + 1]; - - if (imagesPath == NULL) - { - return -1; - } - - strcpy(imagesPath, root_); - strcat(imagesPath, "/images"); - - // - // Check if the cache directory does exist. - // - - struct stat dirStat; - - if (stat(imagesPath, &dirStat) == -1) - { - #ifdef WARNING - *logofs << "Keeper: WARNING! Can't stat NX images cache directory '" - << imagesPath << ". Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Can't stat NX images cache directory '" - << imagesPath << ". Error is " << EGET() << " '" - << ESTR() << "'.\n"; - - delete [] imagesPath; - - return -1; - } - - // - // Check any of the 16 directories in the - // images root path. - // - - char *digitPath = new char[strlen(imagesPath) + 5]; - - strcpy(digitPath, imagesPath); - - for (char digit = 0; digit < 16; digit++) - { - // - // Give up if we received a signal or - // our parent is gone. - // - - if (signal_ != 0) - { - #ifdef TEST - *logofs << "Keeper: Signal detected. Aborting.\n" - << logofs_flush; - #endif - - goto KeeperCleanupImagesAbort; - } - else if (parent_ != getppid() || parent_ == 1) - { - #ifdef WARNING - *logofs << "Keeper: WARNING! Parent process appears " - << "to be dead. Returning.\n" - << logofs_flush; - #endif - - goto KeeperCleanupImagesAbort; - - return 0; - } - - sprintf(digitPath + strlen(imagesPath), "/I-%01X", digit); - - // - // Add to the repository all the files - // in the given directory. - // - - collect(digitPath); - } - - delete [] imagesPath; - delete [] digitPath; - - // - // Remove the oldest files. - // - - cleanup(images_); - - // - // Empty the repository. - // - - empty(); - - return 1; - -KeeperCleanupImagesAbort: - - delete [] imagesPath; - delete [] digitPath; - - empty(); - - return 0; -} - -int Keeper::collect(const char *path) -{ - #ifdef TEST - *logofs << "Keeper: Looking for files in directory '" - << path << "'.\n" << logofs_flush; - #endif - - DIR *cacheDir = opendir(path); - - if (cacheDir != NULL) - { - File *file; - - dirent *dirEntry; - - struct stat fileStat; - - int baseSize = strlen(path); - int fileSize = baseSize + 3 + MD5_LENGTH * 2 + 1; - - int n = 0; - int s = 0; - - while (((dirEntry = readdir(cacheDir)) != NULL)) - { - if (s++ % ONCE == 0) usleep(sleep_ * 1000); - - if (signal_ != 0) break; - - if (strcmp(dirEntry -> d_name, ".") == 0 || - strcmp(dirEntry -> d_name, "..") == 0) - { - continue; - } - - n++; - - if (strlen(dirEntry -> d_name) == (MD5_LENGTH * 2 + 2) && - (strncmp(dirEntry -> d_name, "I-", 2) == 0 || - strncmp(dirEntry -> d_name, "S-", 2) == 0 || - strncmp(dirEntry -> d_name, "C-", 2) == 0)) - { - file = new File(); - - char *fileName = new char[fileSize]; - - if (file == NULL || fileName == NULL) - { - #ifdef WARNING - *logofs << "Keeper: WARNING! Can't add file '" - << dirEntry -> d_name << "' to repository.\n" - << logofs_flush; - #endif - - delete [] fileName; - - delete file; - - continue; - } - - strcpy(fileName, path); - strcpy(fileName + baseSize, "/"); - strcpy(fileName + baseSize + 1, dirEntry -> d_name); - - file -> name_ = fileName; - - #ifdef DEBUG - *logofs << "Keeper: Adding file '" << file -> name_ - << "'.\n" << logofs_flush; - #endif - - if (stat(file -> name_, &fileStat) == -1) - { - #ifdef WARNING - *logofs << "Keeper: WARNING! Can't stat NX file '" - << file -> name_ << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - delete file; - - continue; - } - - file -> size_ = fileStat.st_size; - file -> time_ = fileStat.st_mtime; - - files_ -> insert(T_files::value_type(file)); - - total_ += file -> size_; - } - } - - closedir(cacheDir); - - if (n == 0) - { - time_t now = time(NULL); - - if (now > 0 && stat(path, &fileStat) == 0) - { - #ifdef TEST - *logofs << "Keeper: Empty NX subdirectory '" << path - << "' unused since " << now - fileStat.st_mtime - << " S.\n" << logofs_flush; - #endif - - if (now - fileStat.st_mtime > EMPTY_DIR_TIME) - { - #ifdef TEST - *logofs << "Keeper: Removing empty NX subdirectory '" - << path << "'.\n" << logofs_flush; - #endif - - rmdir(path); - } - } - } - } - else - { - #ifdef WARNING - *logofs << "Keeper: WARNING! Can't open NX subdirectory '" - << path << ". Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Can't open NX subdirectory '" - << path << ". Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - - return 1; -} - -int Keeper::cleanup(int threshold) -{ - #ifdef TEST - *logofs << "Keeper: Deleting the oldest files with " - << files_ -> size() << " elements threshold " - << threshold << " and size " << total_ << ".\n" - << logofs_flush; - #endif - - // - // At least some versions of the standard - // library don't allow erasing an element - // while looping. This is not the most ef- - // ficient way to release the objects, but - // it's better than making a copy of the - // container. - // - - while (total_ > threshold && files_ -> size() > 0) - { - T_files::iterator i = files_ -> begin(); - - File *file = *i; - - #ifdef TEST - *logofs << "Keeper: Removing '" << file -> name_ - << "' with time " << file -> time_ << " and size " - << file -> size_ << ".\n" << logofs_flush; - #endif - - unlink(file -> name_); - - total_ -= file -> size_; - - #ifdef DEBUG - *logofs << "Keeper: Going to delete the file at " - << file << " while cleaning up.\n" - << logofs_flush; - #endif - - delete file; - - #ifdef DEBUG - *logofs << "Keeper: Going to erase the element " - << "while cleaning up.\n" - << logofs_flush; - #endif - - files_ -> erase(i); - } - - #ifdef TEST - *logofs << "Keeper: Bytes in repository are " - << total_ << ".\n" << logofs_flush; - #endif - - return 1; -} - -void Keeper::empty() -{ - #ifdef TEST - *logofs << "Keeper: Getting rid of files in repository.\n" - << logofs_flush; - #endif - - while (files_ -> size() > 0) - { - T_files::iterator i = files_ -> begin(); - - File *file = *i; - - #ifdef DEBUG - *logofs << "Keeper: Going to delete the file at " - << file << " while emptying.\n" - << logofs_flush; - #endif - - delete file; - - #ifdef DEBUG - *logofs << "Keeper: Going to erase the element " - << "while emptying.\n" - << logofs_flush; - #endif - - files_ -> erase(i); - } - - total_ = 0; - - #ifdef TEST - *logofs << "Keeper: Bytes in repository are " - << total_ << ".\n" << logofs_flush; - #endif -} diff --git a/nxcomp/Keeper.h b/nxcomp/Keeper.h deleted file mode 100644 index b440beceb..000000000 --- a/nxcomp/Keeper.h +++ /dev/null @@ -1,199 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Keeper_H -#define Keeper_H - -#include "Misc.h" -#include "Types.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Define this to check how many file -// nodes are allocated and deallocated. -// - -#undef REFERENCES - -class Keeper; - -class File -{ - friend class Keeper; - - public: - - File(); - - ~File(); - - // - // Allow sort by time and size. If time - // is the same, keep the bigger element. - // - - bool compare(File *b) const; - - private: - - char *name_; - - int size_; - time_t time_; - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -class Keeper -{ - public: - - Keeper(int caches, int images, const char *root, - int sleep, int parent); - - ~Keeper(); - - // - // Call this just once. - // - - int cleanupCaches(); - - // - // Call this at any given interval. - // - - int cleanupImages(); - - // - // Call this if it's time to exit. - // - - void setSignal(int signal) - { - signal_ = signal; - } - - int getSignal() - { - return signal_; - } - - int getParent() - { - return parent_; - } - - private: - - // - // Get a list of files in directory. - // - - int collect(const char *path); - - // - // Sort the collected files according to - // last modification time and delete the - // older ones until disk size is below - // the threshold. - // - - int cleanup(int threshold); - - // - // Empty the files repository. - // - - void empty(); - - // - // Size in bytes of total allowed - // storage for persistent caches. - // - - int caches_; - - // - // Size in bytes of total allowed - // storage for images cache. - // - - int images_; - - // - // Path of the NX root directory. - // - - char *root_; - - // - // The little delay to be introduced - // before reading a new entry. - // - - int sleep_; - - // - // Total size of files in repository. - // - - int total_; - - // - // The parent process, so we can exit - // if it is gone. - // - - int parent_; - - // - // Set if we need to give up because - // of a signal. - // - - int signal_; - - // - // Repository where to collect files. - // - - T_files *files_; -}; - -#endif /* Keeper_H */ - diff --git a/nxcomp/List.cpp b/nxcomp/List.cpp deleted file mode 100644 index 228f83214..000000000 --- a/nxcomp/List.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "List.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Define this to know how many instances -// are allocated and deallocated. -// - -#undef REFERENCES - -#ifdef REFERENCES - -int List::references_ = 0; - -#endif - -List::List() -{ - #ifdef REFERENCES - - references_++; - - *logofs << "List: Created new List at " - << this << " out of " << references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -List::~List() -{ - #ifdef REFERENCES - - references_--; - - *logofs << "List: Deleted List at " - << this << " out of " << references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -void List::remove(int value) -{ - for (T_list::iterator i = list_.begin(); i != list_.end(); i++) - { - if (*i == value) - { - list_.erase(i); - - return; - } - } - - #ifdef PANIC - *logofs << "List: PANIC! Should not try to remove " - << "an element not found in the list.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Should not try to remove " - << "an element not found in the list.\n"; - - HandleAbort(); -} - -void List::rotate() -{ - if (list_.size() > 1) - { - int value = *(list_.begin()); - - list_.pop_front(); - - list_.push_back(value); - } -} diff --git a/nxcomp/List.h b/nxcomp/List.h deleted file mode 100644 index 31c80f835..000000000 --- a/nxcomp/List.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef List_H -#define List_H - -#include "Misc.h" -#include "Types.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Define this to log when lists are -// allocated and deallocated. -// - -#undef REFERENCES - -class List -{ - public: - - List(); - - ~List(); - - int getSize() - { - return list_.size(); - } - - T_list &getList() - { - return list_; - } - - T_list copyList() - { - return list_; - } - - void add(int value) - { - list_.push_back(value); - } - - void remove(int value); - - void rotate(); - - private: - - // - // The list container. - // - - T_list list_; - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -#endif /* List_H */ diff --git a/nxcomp/ListFontsReply.cpp b/nxcomp/ListFontsReply.cpp deleted file mode 100644 index 827f68a09..000000000 --- a/nxcomp/ListFontsReply.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ListFontsReply.h" - -#include "ServerCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef DUMP -#undef TEST -#undef DEBUG - -ListFontsReplyStore::ListFontsReplyStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = LISTFONTSREPLY_ENABLE_CACHE; - enableData = LISTFONTSREPLY_ENABLE_DATA; - enableSplit = LISTFONTSREPLY_ENABLE_SPLIT; - - // Since ProtoStep7 (#issue 108) - enableCompress = LISTFONTSREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = LISTFONTSREPLY_DATA_LIMIT; - dataOffset = LISTFONTSREPLY_DATA_OFFSET; - - cacheSlots = LISTFONTSREPLY_CACHE_SLOTS; - cacheThreshold = LISTFONTSREPLY_CACHE_THRESHOLD; - cacheLowerThreshold = LISTFONTSREPLY_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -ListFontsReplyStore::~ListFontsReplyStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int ListFontsReplyStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ListFontsReplyMessage *listFontsReply = (ListFontsReplyMessage *) message; - - // - // Here is the fingerprint. - // - - listFontsReply -> number_of_names = GetUINT(buffer + 8, bigEndian); - - // - // Clean up padding bytes. - // - - if ((int) size > dataOffset) - { - unsigned int current; - unsigned int length; - unsigned int nstringInNames; - - unsigned char *end = NULL; - unsigned char *pad = NULL; - - #ifdef DUMP - - *logofs << "\n" << logofs_flush; - - *logofs << "Number of STRING8 " << listFontsReply -> number_of_names << ".\n" << logofs_flush; - - *logofs << "Size " << size << ".\n" << logofs_flush; - - DumpHexData(buffer, size); - - *logofs << "\n" << logofs_flush; - - #endif - - length = LISTFONTSREPLY_DATA_OFFSET; - - for (nstringInNames = 0; - nstringInNames < listFontsReply -> number_of_names && - listFontsReply -> number_of_names > 0; - nstringInNames++) - { - // - // Start with offset LISTFONTSREPLY_DATA_OFFSET 32. - // - - current = buffer[length]; - - length += current + 1; - - #ifdef DUMP - *logofs << "\nString number : " << nstringInNames << " Current length : " - << current << "\n" << logofs_flush; - #endif - } - - #ifdef DUMP - *logofs << "\nFinal length " << length << "\n" << logofs_flush; - #endif - - end = ((unsigned char *) buffer) + size; - - for (pad = ((unsigned char *) buffer) + length; pad < end; pad++) - { - *pad = 0; - - #ifdef DUMP - *logofs << "\nPadding ." << "\n" << logofs_flush; - #endif - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int ListFontsReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ListFontsReplyMessage *listFontsReply = (ListFontsReplyMessage *) message; - - // - // Fill all the message's fields. - // - - PutUINT(listFontsReply -> number_of_names, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void ListFontsReplyStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - ListFontsReplyMessage *listFontsReply = (ListFontsReplyMessage *) message; - - *logofs << name() << ": Identity number_of_names " - << listFontsReply -> number_of_names << ", size " - << listFontsReply -> size_ << ".\n"; - - #endif -} - -void ListFontsReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Field number_of_names. - // - - md5_append(md5_state_, buffer + 8, 2); -} diff --git a/nxcomp/ListFontsReply.h b/nxcomp/ListFontsReply.h deleted file mode 100644 index c731878e0..000000000 --- a/nxcomp/ListFontsReply.h +++ /dev/null @@ -1,146 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ListFontsReply_H -#define ListFontsReply_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define LISTFONTSREPLY_ENABLE_CACHE 1 -#define LISTFONTSREPLY_ENABLE_DATA 1 -#define LISTFONTSREPLY_ENABLE_SPLIT 0 - -#define LISTFONTSREPLY_DATA_LIMIT 1048576 - 32 -#define LISTFONTSREPLY_DATA_OFFSET 32 - -#define LISTFONTSREPLY_CACHE_SLOTS 200 -#define LISTFONTSREPLY_CACHE_THRESHOLD 20 -#define LISTFONTSREPLY_CACHE_LOWER_THRESHOLD 5 - -#define LISTFONTSREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -// -// The message class. -// - -class ListFontsReplyMessage : public Message -{ - friend class ListFontsReplyStore; - - public: - - ListFontsReplyMessage() - { - } - - ~ListFontsReplyMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned short int number_of_names; -}; - -class ListFontsReplyStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - ListFontsReplyStore(StaticCompressor *compressor); - - virtual ~ListFontsReplyStore(); - - virtual const char *name() const - { - return "ListFontsReply"; - } - - virtual unsigned char opcode() const - { - return X_ListFonts; - } - - virtual unsigned int storage() const - { - return sizeof(ListFontsReplyMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new ListFontsReplyMessage(); - } - - virtual Message *create(const Message &message) const - { - return new ListFontsReplyMessage((const ListFontsReplyMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (ListFontsReplyMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* ListFontsReply_H */ diff --git a/nxcomp/Loop.cpp b/nxcomp/Loop.cpp deleted file mode 100644 index 4592121de..000000000 --- a/nxcomp/Loop.cpp +++ /dev/null @@ -1,16689 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Misc.h" - -#ifdef __sun -#include -#endif - -// -// MacOSX 10.4 defines socklen_t. This is -// intended to ensure compatibility with -// older versions. -// - -#ifdef __APPLE__ -#include -#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3 -typedef int socklen_t; -#endif -#endif - -#ifdef _AIX -#include -#include -#endif - -#ifndef __CYGWIN32__ -#include -#endif - -// -// NX include files. -// - -#include "NX.h" -#include "NXalert.h" - -#include "Misc.h" -#include "Control.h" -#include "Socket.h" -#include "Statistics.h" -#include "Auth.h" -#include "Keeper.h" -#include "Agent.h" - -#include "ClientProxy.h" -#include "ServerProxy.h" - -#include "Message.h" -#include "ChannelEndPoint.h" - -// -// System specific defines. -// - - -// -// HP-UX hides this define. -// - -#if defined(hpux) && !defined(RLIM_INFINITY) - -#define RLIM_INFINITY 0x7fffffff - -#endif - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Enable log output in signal handler. -// This is likely to hang the proxy at -// random, at least on Linux. -// - -#undef UNSAFE - -// -// Let all logs go to the standard error. -// This is useful to interleave the Xlib -// log output with the proxy output in a -// single file. -// - -#undef MIXED - -// -// Define this to check if the client and -// server caches match at shutdown. This -// is a test facility as it requires that -// both proxies are running on the same -// host. -// - -#undef MATCH - -// -// If defined, reduce the size of the log -// file and be sure it never exceeds the -// limit. -// - -#undef QUOTA - -// -// If defined, force very strict limits for -// the proxy tokens and force the proxy to -// enter often in congestion state. -// - -#undef STRICT - -// -// Print a line in the log if the time we -// spent inside the select or handling the -// messages exceeded a given time value. -// - -#undef TIME - -// -// This can be useful when testing the forwarding -// of the SSHD connection by nxssh to the agent. -// The debug output will go to a well known file -// that will be opened also by nxssh when BINDER -// is enabled there. -// - -#undef BINDER - -// -// Define this to override the limits on -// the core dump size. -// - -#define COREDUMPS - -// -// Upper limit of pre-allocated buffers -// for string parameters. -// - -#define DEFAULT_STRING_LENGTH 256 - -// -// Maximum length of remote options data -// passed by peer proxy at startup. -// - -#define DEFAULT_REMOTE_OPTIONS_LENGTH 512 - -// -// Maximum length of NX display string. -// - -#define DEFAULT_DISPLAY_OPTIONS_LENGTH 1024 - -// -// Maximum number of cache file names to -// send to the server side. -// - -#define DEFAULT_REMOTE_CACHE_ENTRIES 100 - -// -// Maximum length of remote options string -// that can be received from the peer proxy. -// - -#define MAXIMUM_REMOTE_OPTIONS_LENGTH 4096 - -// -// Macro is true if we determined our proxy -// mode. -// - -#define WE_SET_PROXY_MODE (control -> ProxyMode != proxy_undefined) - -// -// Macro is true if our side is the one that -// should connect to remote. -// - -#define WE_INITIATE_CONNECTION (connectSocket.enabled()) - -// -// Is true if we must provide our credentials -// to the remote peer. -// - -#define WE_PROVIDE_CREDENTIALS (control -> ProxyMode == proxy_server) - -// -// Is true if we listen for a local forwarder -// that will tunnel the traffic through a SSH -// or HTTP link. -// - -#define WE_LISTEN_FORWARDER (control -> ProxyMode == proxy_server && \ - listenSocket.enabled()) - -// -// You must define FLUSH in Misc.h if -// you want an immediate flush of the -// log output. -// - -ostream *logofs = NULL; - -// -// Other stream destriptors used for -// logging. -// - -ostream *statofs = NULL; -ostream *errofs = NULL; - -// -// Save standard error's rdbuf here -// and restore it when exiting. -// - -static streambuf *errsbuf = NULL; - -// -// Allow faults to be recovered by -// jumping back into the main loop. -// - -jmp_buf context; - -// -// Provide operational parameters. -// - -Control *control = NULL; - -// -// Collect and print statistics. -// - -Statistics *statistics = NULL; - -// -// Keep data for X11 authentication. -// - -Auth *auth = NULL; - -// -// This class makes the hard work. -// - -Proxy *proxy = NULL; - -// -// Used to handle memory-to-memory -// transport to the X agent. -// - -Agent *agent = NULL; - -// -// The image cache house-keeping class. -// - -Keeper *keeper = NULL; - -// -// Callback set by the child process -// to be notified about signals. -// - -int (*handler)(int) = NULL; - -// -// Signal handling functions. -// - -void DisableSignals(); -void EnableSignals(); -void InstallSignals(); - -static void RestoreSignals(); -static void HandleSignal(int signal); - -// -// Signal handling utilities. -// - -static void InstallSignal(int signal, int action); -static void RestoreSignal(int signal); - -static int HandleChildren(); - -int HandleChild(int child); -static int CheckChild(int pid, int status); -static int WaitChild(int child, const char *label, int force); - -int CheckParent(const char *name, const char *type, int parent); - -void RegisterChild(int child); - -static int CheckAbort(); - -// -// Timer handling utilities. -// - -void SetTimer(int timeout); -void ResetTimer(); - -static void HandleTimer(int signal); - -// -// Kill or check a running child. -// - -static int KillProcess(int pid, const char *label, int signal, int wait); -static int CheckProcess(int pid, const char *label); - -// -// Macros used to test the pid of a child. -// - -#define IsFailed(pid) ((pid) < 0) -#define IsRunning(pid) ((pid) > 1) -#define IsNotRunning(pid) ((pid) == 0) -#define IsRestarting(pid) ((pid) == 1) - -#define SetNotRunning(pid) ((pid) = 0) -#define SetRestarting(pid) ((pid) = 1) - -// -// Start or restart the house-keeper process. -// - -static int StartKeeper(); - -// -// Cleanup functions. -// - -void CleanupConnections(); -void CleanupListeners(); -void CleanupSockets(); -void CleanupGlobal(); - -static void CleanupChildren(); -static void CleanupLocal(); -static void CleanupKeeper(); -static void CleanupStreams(); - -// -// Loop forever until the connections -// to the peer proxy is dropped. -// - -static void WaitCleanup(); - -// -// Initialization functions. -// - -static int InitBeforeNegotiation(); -static int SetupProxyConnection(); -static int InitAfterNegotiation(); -static int SetupProxyInstance(); -static int SetupAuthInstance(); -static int SetupAgentInstance(); - -static int SetupTcpSocket(); -static int SetupUnixSocket(); -static int SetupServiceSockets(); -static int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr, - unsigned int &xServerAddrLength); - -// -// Setup a listening socket and accept -// a new connection. -// - -static int ListenConnection(ChannelEndPoint &endPoint, const char *label); -static int ListenConnectionTCP(const char *host, long port, const char *label); -static int ListenConnectionUnix(const char *path, const char *label); -static int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label); -static int AcceptConnection(int fd, int domain, const char *label); - -// -// Other convenience functions. -// - -static int PrepareProxyConnectionTCP(char** hostName, long int* portNum, int* timeout, int* proxyFD, int* reason); -static int PrepareProxyConnectionUnix(char** path, int* timeout, int* proxyFD, int* reason); - -static int WaitForRemote(ChannelEndPoint &socketAddress); -static int ConnectToRemote(ChannelEndPoint &socketAddress); - -static int SendProxyOptions(int fd); -static int SendProxyCaches(int fd); -static int ReadProxyVersion(int fd); -static int ReadProxyOptions(int fd); -static int ReadProxyCaches(int fd); -static int ReadForwarderVersion(int fd); -static int ReadForwarderOptions(int fd); - -static int ReadRemoteData(int fd, char *buffer, int size, char stop); -static int WriteLocalData(int fd, const char *buffer, int size); - -static void PrintVersionInfo(); -static void PrintProcessInfo(); -static void PrintConnectionInfo(); -static void PrintUsageInfo(const char *option, const int error); -static void PrintOptionIgnored(const char *type, const char *name, const char *value); - -// -// This is not static to avoid a warning. -// - -void PrintCopyrightInfo(); - -static const char *GetOptions(const char *options); -static const char *GetArg(int &argi, int argc, const char **argv); -static int CheckArg(const char *type, const char *name, const char *value); -static int ParseArg(const char *type, const char *name, const char *value); -static int ValidateArg(const char *type, const char *name, const char *value); -static void SetAndValidateChannelEndPointArg(const char *type, const char *name, const char *value, - ChannelEndPoint &endPoint); -static int LowercaseArg(const char *type, const char *name, char *value); -static int CheckSignal(int signal); - -extern "C" -{ - int ParseCommandLineOptions(int argc, const char **argv); - int ParseEnvironmentOptions(const char *env, int force); - int ParseBindOptions(char **host, int *port); -} - -static int ParseFileOptions(const char *file); -static int ParseRemoteOptions(char *opts); -static int ParseForwarderOptions(char *opts); - -// -// These functions are used to parse literal -// values provided by the user and set the -// control parameters accordingly. -// - -static int ParseLinkOption(const char *opt); -static int ParseBitrateOption(const char *opt); -static int ParseCacheOption(const char *opt); -static int ParseShmemOption(const char *opt); -static int ParseImagesOption(const char *opt); -static int ParsePackOption(const char *opt); - -// -// Set host and port where NX proxy is supposed -// to be listening in case such parameters are -// given on the command line. -// - -static int ParseHostOption(const char *opt, char *host, long &port); - -// -// Translate a font server port specification -// to the corresponding Unix socket path. -// - -static int ParseFontPath(char *path); - -// -// Translate a pack method id in a literal. -// - -static int ParsePackMethod(const int method, const int quality); - -// -// Try to increase the size of the allowed -// core dumps. -// - -static int SetCore(); - -// -// Set the proxy mode to either client or -// server. -// - -static int SetMode(int mode); - -// -// Determine the path of the NX_* directories -// from the environment. -// - -static int SetDirectories(); - -// -// Set the defaults used for the log file and -// statistics. -// - -static int SetLogs(); - -// -// Check if local and remote protocol versions -// are compatible and, eventually, downgrade -// local version to the minimum level that is -// known to work. -// - -static int SetVersion(); - -// -// Setup the listening TCP ports used for the -// additional channels according to user's -// wishes. -// - -static int SetPorts(); - -// -// Set the maximum number of open descriptors. -// - -static int SetDescriptors(); - -// -// Set the path used for choosing the cache. -// It must be selected after determining the -// session type. -// - -static int SetCaches(); - -// -// Initialize, one after the other, all the -// configuration parameters. -// - -static int SetParameters(); - -// -// Set the specific configuration parameter. -// - -static int SetSession(); -static int SetStorage(); -static int SetShmem(); -static int SetPack(); -static int SetImages(); -static int SetLimits(); - -// -// Set up the control parameters based on -// the link speed negotiated between the -// proxies. -// - -static int SetLink(); - -static int SetLinkModem(); -static int SetLinkIsdn(); -static int SetLinkAdsl(); -static int SetLinkWan(); -static int SetLinkLan(); - -// -// Adjust the compression parameters. -// - -static int SetCompression(); - -static int SetCompressionModem(); -static int SetCompressionIsdn(); -static int SetCompressionAdsl(); -static int SetCompressionWan(); -static int SetCompressionLan(); - -// -// Determine the NX paths based on the -// user's parameters or the environment. -// - -char *GetClientPath(); - -static char *GetSystemPath(); -static char *GetHomePath(); -static char *GetTempPath(); -static char *GetRootPath(); -static char *GetCachePath(); -static char *GetImagesPath(); -static char *GetSessionPath(); -static char *GetLastCache(char *list, const char *path); - -static int OpenLogFile(char *name, ostream *&stream); -static int ReopenLogFile(char *name, ostream *&stream, int limit); - -// -// Perform operations on the managed -// descriptors in the main loop. -// - -static void handleCheckSessionInLoop(); -static void handleCheckBitrateInLoop(); - -#if defined(TEST) || defined(INFO) -static void handleCheckSelectInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, T_timestamp selectTs); -static void handleCheckResultInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs, - struct timeval &startTs); -static void handleCheckStateInLoop(int &setFDs); -#endif - -static void handleCheckSessionInConnect(); - -static inline void handleSetReadInLoop(fd_set &readSet, int &setFDs, struct timeval &selectTs); -static inline void handleSetWriteInLoop(fd_set &writeSet, int &setFDs, struct timeval &selectTs); -static inline void handleSetListenersInLoop(fd_set &writeSet, int &setFDs); -static inline void handleSetAgentInLoop(int &setFDs, fd_set &readSet, fd_set &writeSet, - struct timeval &selectTs); - -static void handleAlertInLoop(); -static void handleStatisticsInLoop(); - -static inline void handleAgentInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs); -static inline void handleAgentLateInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs); - -static inline void handleReadableInLoop(int &resultFDs, fd_set &readSet); -static inline void handleWritableInLoop(int &resultFDs, fd_set &writeSet); - -static inline void handleRotateInLoop(); -static inline void handleEventsInLoop(); -static inline void handleFlushInLoop(); - -// -// Manage the proxy link during the negotiation -// phase. -// - -static void handleNegotiationInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, T_timestamp &selectTs); - -// -// Print the 'terminating' messages in the -// session log. -// - -static inline void handleTerminatingInLoop(); -static inline void handleTerminatedInLoop(); - -// -// Monitor the size of the log file. -// - -static void handleLogReopenInLoop(T_timestamp &logsTs, T_timestamp &nowTs); - -// -// Directory where the NX binaries and libraries reside. -// - -static char systemDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Directory used for temporary files. -// - -static char tempDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Actually the full path to the client. -// - -static char clientDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// User's home directory. -// - -static char homeDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Root of directory structure to be created by proxy. -// - -static char rootDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Root of statistics and log files to be created by proxy. -// - -static char sessionDir[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Log files for errors and statistics. Error log is -// the place where we print also debug informations. -// Both files are closed, deleted and reopened as -// their size exceed the limit set in control class. -// The session log is not reopened, as it is used by -// the NX client and server to track the advance of -// the session. -// - -static char errorsFileName[DEFAULT_STRING_LENGTH] = { 0 }; -static char statsFileName[DEFAULT_STRING_LENGTH] = { 0 }; -static char sessionFileName[DEFAULT_STRING_LENGTH] = { 0 }; -static char optionsFileName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal representing selected link speed -// parameter. Value is translated in control values -// used by proxies to stay synchronized. -// - -static char linkSpeedName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal representing selected -// cache size. -// - -static char cacheSizeName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal representing selected -// shared memory segment size. -// - -static char shsegSizeName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal of images cache size. -// - -static char imagesSizeName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal for bandwidth limit. -// - -static char bitrateLimitName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// String literal for image packing method. -// - -static char packMethodName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Product name provided by the server or client. -// - -static char productName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Its corresponding value from NXpack.h. -// - -static int packMethod = -1; -static int packQuality = -1; - -// -// String literal for session type. Persistent caches -// are searched in directory whose name matches this -// parameter. -// - -static char sessionType[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Unique id assigned to session. It is used as -// name of directory where all files are placed. -// - -static char sessionId[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Set if we already parsed the options. -// - -static int parsedOptions = 0; -static int parsedCommand = 0; - -// -// Buffer data received from the remote proxy at -// session negotiation. -// - -static char remoteData[MAXIMUM_REMOTE_OPTIONS_LENGTH] = { 0 }; -static int remotePosition = 0; - -// -// Main loop file descriptors. -// - -static int tcpFD = -1; -static int unixFD = -1; -static int cupsFD = -1; -static int auxFD = -1; -static int smbFD = -1; -static int mediaFD = -1; -static int httpFD = -1; -static int fontFD = -1; -static int slaveFD = -1; -static int proxyFD = -1; - -// -// Used for internal communication -// with the X agent. -// - -static int agentFD[2] = { -1, -1 }; - -// -// Flags determining which protocols and -// ports are forwarded. -// - -int useUnixSocket = 1; - -static int useTcpSocket = 1; -static int useCupsSocket = 0; -static int useAuxSocket = 0; -static int useSmbSocket = 0; -static int useMediaSocket = 0; -static int useHttpSocket = 0; -static int useFontSocket = 0; -static int useSlaveSocket = 0; -static int useAgentSocket = 0; - -// -// Set if the launchd service is running -// and its socket must be used as X socket. -// - -static int useLaunchdSocket = 0; - -// -// Set by user if he/she wants to modify -// the default TCP_NODELAY option as set -// in control. -// - -static int useNoDelay = -1; - -// -// Set if user wants to override default -// flush timeout set according to link. -// - -static int usePolicy = -1; - -// -// Set if user wants to hide the RENDER -// extension or wants to short-circuit -// some simple replies at client side. -// - -static int useRender = -1; -static int useTaint = -1; - -// -// Set if the user wants to reduce the -// nominal size of the token messages -// exchanged between the proxies. -// - -static int useStrict = -1; - -// -// Set if the proxy is running as part -// of SSH on the client. -// - -static int useEncryption = -1; - -// -// Name of Unix socket created by the client proxy to -// accept client connections. File must be unlinked -// by cleanup function. -// - -static char unixSocketName[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Other parameters. -// - -static char acceptHost[DEFAULT_STRING_LENGTH] = { 0 }; -static char displayHost[DEFAULT_STRING_LENGTH] = { 0 }; -static char authCookie[DEFAULT_STRING_LENGTH] = { 0 }; - -static int loopbackBind = DEFAULT_LOOPBACK_BIND; -static int proxyPort = DEFAULT_NX_PROXY_PORT; -static int xPort = DEFAULT_NX_X_PORT; - -// -// Used to setup the connection the real -// X display socket. -// - -static int xServerAddrFamily = -1; -static sockaddr *xServerAddr = NULL; -static unsigned int xServerAddrLength = 0; - -// -// The representation of a Unix socket path or -// a bind address, denoting where the local proxy -// will await the peer connection. -// - -static ChannelEndPoint listenSocket; - -// -// The TCP host and port or Unix file socket where -// the remote proxy will be contacted. -// - -static ChannelEndPoint connectSocket; - -// -// Helper channels are disabled by default. -// - -static ChannelEndPoint cupsPort; -static ChannelEndPoint auxPort; -static ChannelEndPoint smbPort; -static ChannelEndPoint mediaPort; -static ChannelEndPoint httpPort; -static ChannelEndPoint slavePort; - -// -// Can be either a port number or a Unix -// socket. -// - -static char fontPort[DEFAULT_STRING_LENGTH] = { 0 }; - -// -// Host and port where the existing proxy -// is running. -// - -static char bindHost[DEFAULT_STRING_LENGTH] = { 0 }; -static int bindPort = -1; - -// -// Pointers to the callback functions and -// parameter set by the agent -// - -static void (*flushCallback)(void *, int) = NULL; -static void *flushParameter = NULL; - -static void (*statisticsCallback)(void *, int) = NULL; -static void *statisticsParameter = NULL; - -// -// State variables shared between the init -// function and the main loop. -// - -T_timestamp initTs; -T_timestamp startTs; -T_timestamp logsTs; -T_timestamp nowTs; - -int diffTs; - -// -// This is set to the main proxy process id. -// - -int lastProxy = 0; - -// -// Set to last dialog process launched by proxy. -// - -int lastDialog = 0; - -// -// Set to watchdog process launched by proxy. -// - -int lastWatchdog = 0; - -// -// Set if a cache house-keeper process is running. -// - -int lastKeeper = 0; - -// -// Let an inner routine register the pid of a slave -// process. -// - -static int lastChild = 0; - -// -// Exit code of the last child process exited. -// - -static int lastStatus = 0; - -// -// Set if shutdown was requested through a signal. -// - -static int lastKill = 0; - -// -// Set if the agent confirmed the destruction of -// the NX transport. -// - -static int lastDestroy = 0; - -// -// This is set to the code and local flag of the -// last requested alert. -// - -static struct -{ - int code; - int local; - -} lastAlert; - -// -// Manage the current signal masks. -// - -static struct -{ - sigset_t saved; - - int blocked; - int installed; - - int enabled[32]; - int forward[32]; - - struct sigaction action[32]; - -} lastMasks; - -// -// Manage the current timer. -// - -static struct -{ - struct sigaction action; - struct itimerval value; - struct timeval start; - struct timeval next; - -} lastTimer; - -// -// This is set to last signal received in handler. -// - -static int lastSignal = 0; - -// -// Set to the last time bytes readable were queried -// by the agent. -// - -static T_timestamp lastReadableTs = nullTimestamp(); - -// -// Here are interfaces declared in NX.h. -// - -int NXTransProxy(int fd, int mode, const char* options) -{ - // - // Let the log temporarily go to the standard - // error. Be also sure we have a jump context, - // in the case any subsequent operation will - // cause a cleanup. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - if (setjmp(context) == 1) - { - #ifdef TEST - *logofs << "NXTransProxy: Out of the long jump with pid '" - << lastProxy << "'.\n" << logofs_flush; - #endif - - return -1; - } - - // - // Check if have already performed a parsing of - // parameters, as in the case we are running as - // a stand-alone process. If needed create the - // parameters repository - // - - if (control == NULL) - { - control = new Control(); - } - - lastProxy = getpid(); - - #ifdef TEST - *logofs << "NXTransProxy: Main process started with pid '" - << lastProxy << "'.\n" << logofs_flush; - #endif - - SetMode(mode); - - if (mode == NX_MODE_CLIENT) - { - if (fd != NX_FD_ANY) - { - #ifdef TEST - - *logofs << "NXTransProxy: Agent descriptor for X client connections is FD#" - << fd << ".\n" << logofs_flush; - - *logofs << "NXTransProxy: Disabling listening on further X client connections.\n" - << logofs_flush; - - #endif - - useTcpSocket = 0; - useUnixSocket = 0; - useAgentSocket = 1; - - agentFD[1] = fd; - } - } - else if (mode == NX_MODE_SERVER) - { - if (fd != NX_FD_ANY) - { - #ifdef TEST - *logofs << "NXTransProxy: PANIC! Agent descriptor for X server connections " - << "not supported yet.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Agent descriptor for X server connections " - << "not supported yet.\n"; - - return -1; - } - } - - const char *env = GetOptions(options); - - if (ParseEnvironmentOptions(env, 0) < 0) - { - cerr << "Error" << ": Parsing of NX transport options failed.\n"; - - return -1; - } - - // - // Set the path of the NX directories. - // - - SetDirectories(); - - // - // Open the log files. - // - - SetLogs(); - - #ifdef TEST - *logofs << "NXTransProxy: Going to run the NX transport loop.\n" - << logofs_flush; - #endif - - WaitCleanup(); - - // - // This function should never return. - // - - exit(0); -} - -void NXTransExit(int code) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - static int recurse; - - if (++recurse > 1) - { - #ifdef TEST - *logofs << "NXTransExit: Aborting process with pid '" - << getpid() << "' due to recursion through " - << "exit.\n" << logofs_flush; - #endif - - abort(); - } - - #ifdef TEST - *logofs << "NXTransExit: Process with pid '" - << getpid() << "' called exit with code '" - << code << "'.\n" << logofs_flush; - #endif - - if (control != NULL) - { - // - // Be sure that there we can detect the - // termination of the watchdog. - // - - EnableSignals(); - - // - // Close the NX transport if it was not - // shut down already. - // - - NXTransDestroy(NX_FD_ANY); - } - - exit(code); -} - -int NXTransParseCommandLine(int argc, const char **argv) -{ - return ParseCommandLineOptions(argc, argv); -} - -int NXTransParseEnvironment(const char *env, int force) -{ - return ParseEnvironmentOptions(env, force); -} - -void NXTransCleanup() -{ - HandleCleanup(); -} - -void NXTransCleanupForReconnect() -{ - HandleCleanupForReconnect(); -} - -// -// Check the parameters for subsequent -// initialization of the NX transport. -// - -int NXTransCreate(int fd, int mode, const char* options) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Be sure we have a jump context, in the - // case a subsequent operation will cause - // a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - // - // Create the parameters repository - // - - if (control != NULL) - { - #ifdef PANIC - *logofs << "NXTransCreate: PANIC! The NX transport seems " - << "to be already running.\n" << logofs_flush; - #endif - - cerr << "Error" << ": The NX transport seems " - << "to be already running.\n"; - - return -1; - } - - control = new Control(); - - if (control == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX transport.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX transport.\n"; - - return -1; - } - - lastProxy = getpid(); - - #ifdef TEST - *logofs << "NXTransCreate: Caller process running with pid '" - << lastProxy << "'.\n" << logofs_flush; - #endif - - // - // Set the local proxy mode an parse the - // display NX options. - // - - SetMode(mode); - - const char *env = GetOptions(options); - - if (ParseEnvironmentOptions(env, 0) < 0) - { - cerr << "Error" << ": Parsing of NX transport options failed.\n"; - - return -1; - } - - // - // Set the path of the NX directories. - // - - SetDirectories(); - - // - // Open the log files. - // - - SetLogs(); - - // - // Use the provided descriptor. - // - - proxyFD = fd; - - #ifdef TEST - *logofs << "NXTransCreate: Called with NX proxy descriptor '" - << proxyFD << "'.\n" << logofs_flush; - #endif - - #ifdef TEST - *logofs << "NXTransCreate: Creation of the NX transport completed.\n" - << logofs_flush; - #endif - - return 1; -} - -// -// Tell the proxy to use the descriptor as the internal -// connection to the X client side NX agent. This will -// have the side effect of disabling listening for add- -// itional X client connections. -// - -int NXTransAgent(int fd[2]) -{ - // - // Be sure we have a jump context, in the - // case a subsequent operation will cause - // a cleanup. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - if (setjmp(context) == 1) - { - return -1; - } - - if (control == NULL) - { - cerr << "Error" << ": Can't set the NX agent without a NX transport.\n"; - - return -1; - } - else if (control -> ProxyMode != proxy_client) - { - #ifdef PANIC - *logofs << "NXTransAgent: Invalid mode while setting the NX agent.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid mode while setting the NX agent.\n\n"; - - return -1; - } - - useTcpSocket = 0; - useUnixSocket = 0; - useAgentSocket = 1; - - agentFD[0] = fd[0]; - agentFD[1] = fd[1]; - - #ifdef TEST - - *logofs << "NXTransAgent: Internal descriptors for agent are FD#" - << agentFD[0] << " and FD#" << agentFD[1] << ".\n" - << logofs_flush; - - *logofs << "NXTransAgent: Disabling listening for further X client " - << "connections.\n" << logofs_flush; - - #endif - - agent = new Agent(agentFD); - - if (agent == NULL || agent -> isValid() != 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX memory transport .\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX memory transport.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "NXTransAgent: Enabling memory-to-memory transport.\n" - << logofs_flush; - #endif - - return 1; -} - -int NXTransClose(int fd) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - /* - * Only handle the proxy connection. The X - * transport will take care of closing its - * end of the socket pair. - */ - - if (control != NULL && ((agent != NULL && - (fd == agentFD[0] || fd == NX_FD_ANY)) || - (fd == proxyFD || fd == NX_FD_ANY))) - { - if (proxy != NULL) - { - #ifdef TEST - *logofs << "NXTransClose: Closing down all the X connections.\n" - << logofs_flush; - #endif - - CleanupConnections(); - } - } - #ifdef TEST - else - { - *logofs << "NXTransClose: The NX transport is not running.\n" - << logofs_flush; - } - #endif - - return 1; -} - -// -// Close down the transport and free the -// allocated NX resources. -// - -int NXTransDestroy(int fd) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control != NULL && ((agent != NULL && - (fd == agentFD[0] || fd == NX_FD_ANY)) || - (fd == proxyFD || fd == NX_FD_ANY))) - { - // - // Shut down the X connections and - // wait the cleanup to complete. - // - - if (proxy != NULL) - { - #ifdef TEST - *logofs << "NXTransDestroy: Closing down all the X connections.\n" - << logofs_flush; - #endif - - CleanupConnections(); - } - - #ifdef TEST - *logofs << "NXTransDestroy: Waiting for the NX transport to terminate.\n" - << logofs_flush; - #endif - - lastDestroy = 1; - - WaitCleanup(); - } - #ifdef TEST - else - { - *logofs << "NXTransDestroy: The NX transport is not running.\n" - << logofs_flush; - } - #endif - - return 1; -} - -// -// Assume that the NX transport is valid -// as long as the control class has not -// been destroyed. -// - -int NXTransRunning(int fd) -{ - return (control != NULL); -} - -int NXTransContinue(struct timeval *selectTs) -{ - if (control != NULL) - { - // - // If no timeout is provided use - // the default. - // - - T_timestamp newTs; - - if (selectTs == NULL) - { - setTimestamp(newTs, control -> PingTimeout); - - selectTs = &newTs; - } - - // - // Use empty masks and only get the - // descriptors set by the proxy. - // - - fd_set readSet; - fd_set writeSet; - - int setFDs; - int errorFDs; - int resultFDs; - - setFDs = 0; - - FD_ZERO(&readSet); - FD_ZERO(&writeSet); - - // - // Run a new loop. If the transport - // is gone avoid sleeping until the - // timeout. - // - - if (NXTransPrepare(&setFDs, &readSet, &writeSet, selectTs) != 0) - { - NXTransSelect(&resultFDs, &errorFDs, &setFDs, &readSet, &writeSet, selectTs); - - NXTransExecute(&resultFDs, &errorFDs, &setFDs, &readSet, &writeSet, selectTs); - } - } - - return (control != NULL); -} - -int NXTransSignal(int signal, int action) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control == NULL) - { - return 0; - } - - if (action == NX_SIGNAL_RAISE) - { - #ifdef TEST - *logofs << "NXTransSignal: Raising signal '" << DumpSignal(signal) - << "' in the proxy handler.\n" << logofs_flush; - #endif - - HandleSignal(signal); - - return 1; - } - else if (signal == NX_SIGNAL_ANY) - { - #ifdef TEST - *logofs << "NXTransSignal: Setting action of all signals to '" - << action << "'.\n" << logofs_flush; - #endif - - for (int i = 0; i < 32; i++) - { - if (CheckSignal(i) == 1) - { - NXTransSignal(i, action); - } - } - - return 1; - } - else if (CheckSignal(signal) == 1) - { - #ifdef TEST - *logofs << "NXTransSignal: Setting action of signal '" - << DumpSignal(signal) << "' to '" << action - << "'.\n" << logofs_flush; - #endif - - if (action == NX_SIGNAL_ENABLE || - action == NX_SIGNAL_FORWARD) - { - InstallSignal(signal, action); - - return 1; - } - else if (action == NX_SIGNAL_DISABLE) - { - RestoreSignal(signal); - - return 1; - } - } - - #ifdef WARNING - *logofs << "NXTransSignal: WARNING! Unable to perform action '" - << action << "' on signal '" << DumpSignal(signal) - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Unable to perform action '" << action - << "' on signal '" << DumpSignal(signal) - << "'.\n"; - - return -1; -} - -int NXTransCongestion(int fd) -{ - if (control != NULL && proxy != NULL) - { - #ifdef DUMP - - int congestion = proxy -> getCongestion(proxyFD); - - *logofs << "NXTransCongestion: Returning " << congestion - << " as current congestion level.\n" << logofs_flush; - - return congestion; - - #endif - - return (proxy -> getCongestion(proxyFD)); - } - - return 0; -} - -int NXTransHandler(int fd, int type, void (*handler)(void *parameter, - int reason), void *parameter) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - switch (type) - { - case NX_HANDLER_FLUSH: - { - flushCallback = handler; - flushParameter = parameter; - - break; - } - case NX_HANDLER_STATISTICS: - { - // - // Reporting of statistics by the agent - // still needs to be implemented. - // - - statisticsCallback = handler; - statisticsParameter = parameter; - - break; - } - default: - { - #ifdef TEST - *logofs << "NXTransHandler: WARNING! Failed to set " - << "the NX callback for event '" << type << "' to '" - << (void *) handler << "' and parameter '" - << parameter << "'.\n" << logofs_flush; - #endif - - return 0; - } - } - - #ifdef TEST - *logofs << "NXTransHandler: Set the NX " - << "callback for event '" << type << "' to '" - << (void *) handler << "' and parameter '" - << parameter << "'.\n" << logofs_flush; - #endif - - return 1; -} - -int NXTransRead(int fd, char *data, int size) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control != NULL && agent != NULL && - fd == agentFD[0]) - { - #ifdef DUMP - *logofs << "NXTransRead: Dequeuing " << size << " bytes " - << "from FD#" << agentFD[0] << ".\n" << logofs_flush; - #endif - - int result = agent -> dequeueData(data, size); - - #ifdef DUMP - - if (result < 0 && EGET() == EAGAIN) - { - *logofs << "NXTransRead: WARNING! Dequeuing from FD#" - << agentFD[0] << " would block.\n" << logofs_flush; - } - else - { - *logofs << "NXTransRead: Dequeued " << result << " bytes " - << "to FD#" << agentFD[0] << ".\n" << logofs_flush; - } - - #endif - - return result; - } - else - { - #ifdef DUMP - *logofs << "NXTransRead: Reading " << size << " bytes " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - return read(fd, data, size); - } -} - -int NXTransReadVector(int fd, struct iovec *iovdata, int iovsize) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control != NULL && agent != NULL && - fd == agentFD[0]) - { - #if defined(DUMP) - - if (control -> ProxyStage >= stage_operational && - agent -> localReadable() > 0) - { - *logofs << "NXTransReadVector: WARNING! Agent has data readable.\n" - << logofs_flush; - } - - #endif - - char *base; - - int length; - int result; - - struct iovec *vector = iovdata; - int count = iovsize; - - ESET(0); - - int i = 0; - int total = 0; - - for (; i < count; i++, vector++) - { - length = vector -> iov_len; - base = (char *) vector -> iov_base; - - while (length > 0) - { - #ifdef DUMP - *logofs << "NXTransReadVector: Dequeuing " << length - << " bytes " << "from FD#" << agentFD[0] << ".\n" - << logofs_flush; - #endif - - result = agent -> dequeueData(base, length); - - #ifdef DUMP - - if (result < 0 && EGET() == EAGAIN) - { - *logofs << "NXTransReadVector: WARNING! Dequeuing from FD#" - << agentFD[0] << " would block.\n" << logofs_flush; - } - else - { - *logofs << "NXTransReadVector: Dequeued " << result - << " bytes " << "from FD#" << agentFD[0] << ".\n" - << logofs_flush; - } - - #endif - - if (result < 0 && total == 0) - { - return result; - } - else if (result <= 0) - { - return total; - } - - ESET(0); - - length -= result; - total += result; - base += result; - } - } - - return total; - } - else - { - #ifdef DUMP - *logofs << "NXTransReadVector: Reading vector with " - << iovsize << " elements from FD#" << fd << ".\n" - << logofs_flush; - #endif - - return readv(fd, iovdata, iovsize); - } -} - -int NXTransReadable(int fd, int *readable) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control == NULL || agent == NULL || - fd != agentFD[0]) - { - #ifdef DUMP - - int result = GetBytesReadable(fd, readable); - - if (result == -1) - { - *logofs << "NXTransReadable: Error detected on FD#" - << fd << ".\n" << logofs_flush; - } - else - { - *logofs << "NXTransReadable: Returning " << *readable - << " bytes as readable from FD#" << fd - << ".\n" << logofs_flush; - } - - return result; - - #else - - return GetBytesReadable(fd, readable); - - #endif - } - - int result = agent -> dequeuableData(); - - switch (result) - { - case 0: - { - // - // The client might have enqueued data to our side - // and is now checking for the available events. As - // _XEventsQueued() may omit to call _XSelect(), we - // handle here the new data that is coming from the - // proxy to avoid spinning through this function - // again. - // - - if (proxy != NULL && proxy -> canRead() == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransReadable: WARNING! Trying to " - << "read to generate new agent data.\n" - << logofs_flush; - #endif - - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - if (proxy -> handleRead() < 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransReadable: Failure reading " - << "messages from proxy FD#" << proxyFD - << ".\n" << logofs_flush; - #endif - - HandleShutdown(); - } - - // - // Call again the routine. By reading - // new control messages from the proxy - // the agent channel may be gone. - // - - return NXTransReadable(fd, readable); - } - - #ifdef DUMP - *logofs << "NXTransReadable: Returning " << 0 - << " bytes as readable from FD#" << fd - << " with result 0.\n" << logofs_flush; - #endif - - *readable = 0; - - return 0; - } - case -1: - { - #ifdef DUMP - *logofs << "NXTransReadable: Returning " << 0 - << " bytes as readable from FD#" << fd - << " with result -1.\n" << logofs_flush; - #endif - - *readable = 0; - - return -1; - } - default: - { - #ifdef DUMP - *logofs << "NXTransReadable: Returning " << result - << " bytes as readable from FD#" << fd - << " with result 0.\n" << logofs_flush; - #endif - - *readable = result; - - return 0; - } - } -} - -int NXTransWrite(int fd, char *data, int size) -{ - // - // Be sure we have a valid log file. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - if (control != NULL && agent != NULL && - fd == agentFD[0]) - { - int result; - - if (proxy != NULL) - { - if (proxy -> canRead(agentFD[1]) == 0) - { - #if defined(DUMP) || defined(TEST) - *logofs << "NXTransWrite: WARNING! Delayed enqueuing to FD#" - << agentFD[0] << " with proxy unable to read.\n" - << logofs_flush; - #endif - - ESET(EAGAIN); - - return -1; - } - - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - // - // Don't enqueue the data to the transport - // but let the channel borrow the buffer. - // - - #ifdef DUMP - *logofs << "NXTransWrite: Letting the channel borrow " - << size << " bytes from FD#" << agentFD[0] - << ".\n" << logofs_flush; - #endif - - result = proxy -> handleRead(agentFD[1], data, size); - - if (result == 1) - { - result = size; - } - else - { - if (result == 0) - { - ESET(EAGAIN); - } - else - { - ESET(EPIPE); - } - - result = -1; - } - } - else - { - // - // We don't have a proxy connection, yet. - // Enqueue the data to the agent transport. - // - - #ifdef DUMP - *logofs << "NXTransWrite: Enqueuing " << size << " bytes " - << "to FD#" << agentFD[0] << ".\n" << logofs_flush; - #endif - - result = agent -> enqueueData(data, size); - } - - #ifdef DUMP - - if (result < 0) - { - if (EGET() == EAGAIN) - { - *logofs << "NXTransWrite: WARNING! Enqueuing to FD#" - << agentFD[0] << " would block.\n" - << logofs_flush; - } - else - { - *logofs << "NXTransWrite: WARNING! Error enqueuing to FD#" - << agentFD[0] << ".\n" << logofs_flush; - } - } - else - { - *logofs << "NXTransWrite: Enqueued " << result << " bytes " - << "to FD#" << agentFD[0] << ".\n" << logofs_flush; - } - - #endif - - return result; - } - else - { - #ifdef DUMP - *logofs << "NXTransWrite: Writing " << size << " bytes " - << "to FD#" << fd << ".\n" << logofs_flush; - #endif - - return write(fd, data, size); - } -} - -int NXTransWriteVector(int fd, struct iovec *iovdata, int iovsize) -{ - // - // Be sure we have a valid log file and a - // jump context because we will later call - // functions that can perform a cleanup. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - int result = 0; - - if (control != NULL && agent != NULL && - fd == agentFD[0]) - { - // - // See the comment in NXTransWrite(). - // - - if (proxy != NULL) - { - if (proxy -> canRead(agentFD[1]) == 0) - { - #if defined(DUMP) || defined(TEST) - *logofs << "NXTransWriteVector: WARNING! Delayed enqueuing to FD#" - << agentFD[0] << " with proxy unable to read.\n" - << logofs_flush; - #endif - - ESET(EAGAIN); - - return -1; - } - } - - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - char *base; - - int length; - - struct iovec *vector = iovdata; - int count = iovsize; - - ESET(0); - - int i = 0; - int total = 0; - - for (; i < count; i++, vector++) - { - length = vector -> iov_len; - base = (char *) vector -> iov_base; - - while (length > 0) - { - if (proxy != NULL) - { - // - // Don't enqueue the data to the transport - // but let the channel borrow the buffer. - // - - #ifdef DUMP - *logofs << "NXTransWriteVector: Letting the channel borrow " - << length << " bytes from FD#" << agentFD[0] - << ".\n" << logofs_flush; - #endif - - result = proxy -> handleRead(agentFD[1], base, length); - - if (result == 1) - { - result = length; - } - else - { - if (result == 0) - { - ESET(EAGAIN); - } - else - { - ESET(EPIPE); - } - - result = -1; - } - } - else - { - // - // We don't have a proxy connection, yet. - // Enqueue the data to the agent transport. - // - - #ifdef DUMP - *logofs << "NXTransWriteVector: Enqueuing " << length - << " bytes " << "to FD#" << agentFD[0] << ".\n" - << logofs_flush; - #endif - - result = agent -> enqueueData(base, length); - } - - #ifdef DUMP - - if (result < 0) - { - if (EGET() == EAGAIN) - { - *logofs << "NXTransWriteVector: WARNING! Enqueuing to FD#" - << agentFD[0] << " would block.\n" - << logofs_flush; - } - else - { - *logofs << "NXTransWriteVector: WARNING! Error enqueuing to FD#" - << agentFD[0] << ".\n" << logofs_flush; - } - } - else - { - *logofs << "NXTransWriteVector: Enqueued " << result - << " bytes " << "to FD#" << agentFD[0] << ".\n" - << logofs_flush; - } - - #endif - - if (result < 0 && total == 0) - { - return result; - } - else if (result <= 0) - { - return total; - } - - ESET(0); - - length -= result; - total += result; - base += result; - } - } - - return total; - } - else - { - #ifdef DUMP - *logofs << "NXTransWriteVector: Writing vector with " - << iovsize << " elements to FD#" << fd << ".\n" - << logofs_flush; - #endif - - return writev(fd, iovdata, iovsize); - } -} - -int NXTransPolicy(int fd, int type) -{ - if (control != NULL) - { - if (usePolicy == -1) - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransPolicy: Setting flush policy on " - << "proxy FD#" << proxyFD << " to '" - << DumpPolicy(type == NX_POLICY_DEFERRED ? - policy_deferred : policy_immediate) - << "'.\n" << logofs_flush; - #endif - - control -> FlushPolicy = (type == NX_POLICY_DEFERRED ? - policy_deferred : policy_immediate); - - if (proxy != NULL) - { - proxy -> handleFlush(); - } - - return 1; - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransPolicy: Ignoring the agent " - << "setting with user policy set to '" - << DumpPolicy(control -> FlushPolicy) - << "'.\n" << logofs_flush; - #endif - - return 0; - } - } - - return 0; -} - -int NXTransFlushable(int fd) -{ - if (proxy == NULL || agent == NULL || - fd != agentFD[0]) - { - #ifdef DUMP - *logofs << "NXTransFlushable: Returning 0 bytes as " - << "flushable for unrecognized FD#" << fd - << ".\n" << logofs_flush; - #endif - - return 0; - } - else - { - #if defined(DUMP) || defined(INFO) - *logofs << "NXTransFlushable: Returning " << proxy -> - getFlushable(proxyFD) << " as bytes flushable on " - << "proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - return proxy -> getFlushable(proxyFD); - } -} - -int NXTransFlush(int fd) -{ - if (proxy != NULL) - { - #if defined(TEST) || defined(INFO) - *logofs << "NXTransFlush: Requesting an immediate flush of " - << "proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - return proxy -> handleFlush(); - } - - return 0; -} - -int NXTransChannel(int fd, int channelFd, int type) -{ - if (proxy != NULL) - { - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - #if defined(TEST) || defined(INFO) - *logofs << "NXTransChannel: Going to create a new channel " - << "with type '" << type << "' on FD#" << channelFd - << ".\n" << logofs_flush; - #endif - - int result = -1; - - switch (type) - { - case NX_CHANNEL_X11: - { - if (useUnixSocket == 1 || useTcpSocket == 1 || - useAgentSocket == 1 || useAuxSocket == 1) - { - result = proxy -> handleNewConnection(channel_x11, channelFd); - } - - break; - } - case NX_CHANNEL_CUPS: - { - if (useCupsSocket == 1) - { - result = proxy -> handleNewConnection(channel_cups, channelFd); - } - - break; - } - case NX_CHANNEL_SMB: - { - if (useSmbSocket == 1) - { - result = proxy -> handleNewConnection(channel_smb, channelFd); - } - - break; - } - case NX_CHANNEL_MEDIA: - { - if (useMediaSocket == 1) - { - result = proxy -> handleNewConnection(channel_media, channelFd); - } - - break; - } - case NX_CHANNEL_HTTP: - { - if (useHttpSocket == 1) - { - result = proxy -> handleNewConnection(channel_http, channelFd); - } - - break; - } - case NX_CHANNEL_FONT: - { - if (useFontSocket == 1) - { - result = proxy -> handleNewConnection(channel_font, channelFd); - } - - break; - } - case NX_CHANNEL_SLAVE: - { - if (useSlaveSocket == 1) - { - result = proxy -> handleNewConnection(channel_slave, channelFd); - } - - break; - } - default: - { - #ifdef WARNING - *logofs << "NXTransChannel: WARNING! Unrecognized channel " - << "type '" << type << "'.\n" << logofs_flush; - #endif - - break; - } - } - - #ifdef WARNING - - if (result != 1) - { - *logofs << "NXTransChannel: WARNING! Could not create the " - << "new channel with type '" << type << "' on FD#" - << channelFd << ".\n" << logofs_flush; - } - - #endif - - return result; - } - - return 0; -} - -const char *NXTransFile(int type) -{ - char *name = NULL; - - switch (type) - { - case NX_FILE_SESSION: - { - name = sessionFileName; - - break; - } - case NX_FILE_ERRORS: - { - name = errorsFileName; - - break; - } - case NX_FILE_OPTIONS: - { - name = optionsFileName; - - break; - } - case NX_FILE_STATS: - { - name = statsFileName; - - break; - } - } - - if (name != NULL && *name != '\0') - { - return name; - } - - return NULL; -} - -long NXTransTime() -{ - static T_timestamp last = getTimestamp(); - - T_timestamp now = getTimestamp(); - - long diff = diffTimestamp(last, now); - - last = now; - - return diff; -} - -int NXTransAlert(int code, int local) -{ - if (proxy != NULL) - { - #if defined(DUMP) || defined(INFO) - *logofs << "NXTransAlert: Requesting a NX dialog with code " - << code << " and local " << local << ".\n" - << logofs_flush; - #endif - - if (local == 0) - { - // - // Set the context as the function - // can cause a cleanup. - // - - if (setjmp(context) == 1) - { - return -1; - } - - proxy -> handleAlert(code); - } - else - { - // - // Show the alert at the next loop. - // - - HandleAlert(code, local); - } - - return 1; - } - #if defined(DUMP) || defined(INFO) - else - { - if (logofs == NULL) - { - logofs = &cerr; - } - - *logofs << "NXTransAlert: Can't request an alert without " - << "a valid NX transport.\n" << logofs_flush; - } - #endif - - return 0; -} - -// -// Prepare the file sets and the timeout -// for a later execution of the select(). -// - -int NXTransPrepare(int *setFDs, fd_set *readSet, - fd_set *writeSet, struct timeval *selectTs) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Control is NULL if the NX transport was - // reset or was never created. If control - // is valid then prepare to jump back when - // the transport is destroyed. - // - - if (control == NULL || setjmp(context) == 1) - { - return 0; - } - - #if defined(TEST) || defined(INFO) - *logofs << "\nNXTransPrepare: Going to prepare the NX transport.\n" - << logofs_flush; - #endif - - if (control -> ProxyStage < stage_operational) - { - handleNegotiationInLoop(*setFDs, *readSet, *writeSet, *selectTs); - } - else - { - #if defined(TEST) || defined(INFO) - - if (isTimestamp(*selectTs) == 0) - { - *logofs << "Loop: WARNING! Preparing the select with requested " - << "timeout of " << selectTs -> tv_sec << " S and " - << (double) selectTs -> tv_usec / 1000 << " Ms.\n" - << logofs_flush; - } - else - { - *logofs << "Loop: Preparing the select with requested " - << "timeout of " << selectTs -> tv_sec << " S and " - << (double) selectTs -> tv_usec / 1000 << " Ms.\n" - << logofs_flush; - } - - #endif - - // - // Set descriptors of listening sockets. - // - - handleSetListenersInLoop(*readSet, *setFDs); - - // - // Set descriptors of both proxy and X - // connections. - // - - handleSetReadInLoop(*readSet, *setFDs, *selectTs); - - // - // Find out which file descriptors have - // data to write. - // - - handleSetWriteInLoop(*writeSet, *setFDs, *selectTs); - } - - // - // Prepare the masks for handling the memory- - // to-memory transport. This is required even - // during session negotiation. - // - - if (agent != NULL) - { - handleSetAgentInLoop(*setFDs, *readSet, *writeSet, *selectTs); - } - - // - // Register time spent handling messages. - // - - nowTs = getNewTimestamp(); - - diffTs = diffTimestamp(startTs, nowTs); - - #ifdef TEST - *logofs << "Loop: Mark - 0 - at " << strMsTimestamp() - << " with " << diffTs << " Ms elapsed.\n" - << logofs_flush; - #endif - - // - // TODO: Should add the read time in two - // parts otherwise the limits are checked - // before the counters are updated with - // time spent in the last loop. - // - - if (control -> ProxyStage >= stage_operational) - { - statistics -> addReadTime(diffTs); - } - - startTs = nowTs; - - #ifdef DEBUG - *logofs << "Loop: New timestamp is " << strMsTimestamp(startTs) - << ".\n" << logofs_flush; - #endif - - return 1; -} - -// -// Let's say that we call select() to find out -// if any of the handled descriptors has data, -// but actually things are a bit more complex -// than that. -// - -int NXTransSelect(int *resultFDs, int *errorFDs, int *setFDs, fd_set *readSet, - fd_set *writeSet, struct timeval *selectTs) -{ - #ifdef TIME - - static T_timestamp lastTs; - - #endif - - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Control is NULL if the NX transport was - // reset or never created. If control is - // valid then prepare for jumping back in - // the case of an error. - // - - if (control == NULL || setjmp(context) == 1) - { - *resultFDs = select(*setFDs, readSet, writeSet, NULL, selectTs); - - *errorFDs = errno; - - return 0; - } - - #if defined(TEST) || defined(INFO) - *logofs << "\nNXTransSelect: Going to select the NX descriptors.\n" - << logofs_flush; - #endif - - #if defined(TEST) || defined(INFO) - - handleCheckSelectInLoop(*setFDs, *readSet, *writeSet, *selectTs); - - #endif - - #ifdef TIME - - diffTs = diffTimestamp(lastTs, getNewTimestamp()); - - if (diffTs > 20) - { - *logofs << "Loop: TIME! Spent " << diffTs - << " Ms handling messages for proxy FD#" - << proxyFD << ".\n" << logofs_flush; - } - - lastTs = getNewTimestamp(); - - #endif - - #if defined(TEST) || defined(INFO) - - if (isTimestamp(*selectTs) == 0) - { - *logofs << "Loop: WARNING! Executing the select with requested " - << "timeout of " << selectTs -> tv_sec << " S and " - << (double) selectTs -> tv_usec / 1000 << " Ms.\n" - << logofs_flush; - } - else if (proxy != NULL && proxy -> getFlushable(proxyFD) > 0) - { - *logofs << "Loop: WARNING! Proxy FD#" << proxyFD - << " has " << proxy -> getFlushable(proxyFD) - << " bytes to write but timeout is " - << selectTs -> tv_sec << " S and " - << selectTs -> tv_usec / 1000 << " Ms.\n" - << logofs_flush; - } - - #endif - - // - // Wait for the selected sockets - // or the timeout. - // - - ESET(0); - - *resultFDs = select(*setFDs, readSet, writeSet, NULL, selectTs); - - *errorFDs = EGET(); - - #ifdef TIME - - diffTs = diffTimestamp(lastTs, getNewTimestamp()); - - if (diffTs > 100) - { - *logofs << "Loop: TIME! Spent " << diffTs - << " Ms waiting for new data for proxy FD#" - << proxyFD << ".\n" << logofs_flush; - } - - lastTs = getNewTimestamp(); - - #endif - - // - // Check the result of the select. - // - - #if defined(TEST) || defined(INFO) - - handleCheckResultInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs, startTs); - - #endif - - // - // Get time spent in select. The accouting is done - // in milliseconds. This is a real problem on fast - // machines where each loop is unlikely to take - // more than 500 us, so consider that the results - // can be inaccurate. - // - - nowTs = getNewTimestamp(); - - diffTs = diffTimestamp(startTs, nowTs); - - #ifdef TEST - *logofs << "Loop: Out of select after " << diffTs << " Ms " - << "at " << strMsTimestamp(nowTs) << " with result " - << *resultFDs << ".\n" << logofs_flush; - #endif - - startTs = nowTs; - - #ifdef DEBUG - *logofs << "Loop: New timestamp is " << strMsTimestamp(startTs) - << ".\n" << logofs_flush; - #endif - - if (control -> ProxyStage >= stage_operational) - { - statistics -> addIdleTime(diffTs); - } - - if (*resultFDs < 0) - { - // - // Check if the call was interrupted or if any of the - // managed descriptors has become invalid. This can - // happen to the X11 code, before the descriptor is - // removed from the managed set. - // - - #ifdef __sun - - if (*errorFDs == EINTR || *errorFDs == EBADF || - *errorFDs == EINVAL) - - #else - - if (*errorFDs == EINTR || *errorFDs == EBADF) - - #endif - - { - #ifdef TEST - - if (*errorFDs == EINTR) - { - *logofs << "Loop: Select failed due to EINTR error.\n" - << logofs_flush; - } - else - { - *logofs << "Loop: WARNING! Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - } - - #endif - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - HandleCleanup(); - } - } - - return 1; -} - -// -// Perform the required actions on all -// the descriptors having I/O pending. -// - -int NXTransExecute(int *resultFDs, int *errorFDs, int *setFDs, fd_set *readSet, - fd_set *writeSet, struct timeval *selectTs) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Control is NULL if the NX transport was - // reset or never created. If control is - // valid then prepare for jumping back in - // the case of an error. - // - - if (control == NULL || setjmp(context) == 1) - { - return 0; - } - - #if defined(TEST) || defined(INFO) - *logofs << "\nNXTransExecute: Going to execute I/O on the NX descriptors.\n" - << logofs_flush; - #endif - - if (control -> ProxyStage >= stage_operational) - { - // - // Check if I/O is possible on the proxy and - // local agent descriptors. - // - - if (agent != NULL) - { - handleAgentInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs); - } - - #ifdef TEST - *logofs << "Loop: Mark - 1 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Rotate the channel that will be handled - // first. - // - - handleRotateInLoop(); - - // - // Flush any data on newly writable sockets. - // - - handleWritableInLoop(*resultFDs, *writeSet); - - #ifdef TEST - *logofs << "Loop: Mark - 2 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Check if any socket has become readable. - // - - handleReadableInLoop(*resultFDs, *readSet); - - #ifdef TEST - *logofs << "Loop: Mark - 3 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Handle the scheduled events on channels. - // - // - Restart, if possible, any client that was - // put to sleep. - // - // - Check if there are pointer motion events to - // flush. This applies only to X server side. - // - // - Check if any channel has exited the conges- - // tion state. - // - // - Check if there are images that are currently - // being streamed. - // - - handleEventsInLoop(); - - #ifdef TEST - *logofs << "Loop: Mark - 4 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Check if user sent a signal to produce - // statistics. - // - - handleStatisticsInLoop(); - - // - // We may have flushed the proxy link or - // handled data coming from the remote. - // Post-process the masks and set the - // selected agent descriptors as ready. - // - - if (agent != NULL) - { - handleAgentLateInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs); - } - - #ifdef TEST - *logofs << "Loop: Mark - 5 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - - // - // Check if there is any data to flush. - // Agents should flush the proxy link - // explicitly. - // - - handleFlushInLoop(); - - #ifdef TEST - *logofs << "Loop: Mark - 6 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - } - - // - // Check if we have an alert to show. - // - - handleAlertInLoop(); - - if (control -> ProxyStage >= stage_operational) - { - // - // Check if it's time to give up. - // - - handleCheckSessionInLoop(); - - // - // Check if local proxy is consuming - // too many resources. - // - - handleCheckBitrateInLoop(); - - // - // Check coherency of internal state. - // - - #if defined(TEST) || defined(INFO) - - handleCheckStateInLoop(*setFDs); - - #endif - - #ifdef TEST - *logofs << "Loop: Mark - 7 - at " << strMsTimestamp() - << " with " << diffTimestamp(startTs, getTimestamp()) - << " Ms elapsed.\n" << logofs_flush; - #endif - } - - // - // Truncate the logs if needed. - // - - handleLogReopenInLoop(logsTs, nowTs); - - return 1; -} - -// -// Initialize the connection parameters and -// prepare for negotiating the link with the -// remote proxy. -// - -int InitBeforeNegotiation() -{ - // - // Disable limits on core dumps. - // - - SetCore(); - - // - // Install the signal handlers. - // - - InstallSignals(); - - // - // Track how much time we spent in initialization. - // - - nowTs = getNewTimestamp(); - - startTs = nowTs; - initTs = nowTs; - - #ifdef TEST - *logofs << "Loop: INIT! Taking mark for initialization at " - << strMsTimestamp(initTs) << ".\n" - << logofs_flush; - #endif - - // - // If not explicitly specified, determine if local - // mode is client or server according to parameters - // provided so far. - // - - if (WE_SET_PROXY_MODE == 0) - { - cerr << "Error" << ": Please specify either the -C or -S option.\n"; - - HandleCleanup(); - } - - // - // Start a watchdog. If initialization cannot - // be completed before timeout, then clean up - // everything and exit. - // - - if (control -> ProxyMode == proxy_client) - { - #ifdef TEST - *logofs << "Loop: Starting watchdog process with timeout of " - << control -> InitTimeout / 1000 << " seconds.\n" - << logofs_flush; - #endif - - lastWatchdog = NXTransWatchdog(control -> InitTimeout); - - if (IsFailed(lastWatchdog)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't start the NX watchdog process.\n" - << logofs_flush; - #endif - - SetNotRunning(lastWatchdog); - } - #ifdef TEST - else - { - *logofs << "Loop: Watchdog started with pid '" - << lastWatchdog << "'.\n" << logofs_flush; - } - #endif - } - - // - // Print preliminary info. - // - - PrintProcessInfo(); - - // - // Set cups, multimedia and other - // auxiliary ports. - // - - SetPorts(); - - // - // Increase the number of maximum open - // file descriptors for this process. - // - - SetDescriptors(); - - // - // Set local endianess. - // - - unsigned int test = 1; - - setHostBigEndian(*((unsigned char *) (&test)) == 0); - - #ifdef TEST - *logofs << "Loop: Local host is " - << (hostBigEndian() ? "big endian" : "little endian") - << ".\n" << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_client) - { - // - // Listen on sockets that mimic an X display to - // which X clients will be able to connect (e.g. - // unix:8 and/or localhost:8). - // - - if (useTcpSocket == 1) - { - SetupTcpSocket(); - } - - if (useUnixSocket == 1) - { - SetupUnixSocket(); - } - } - else - { - // - // Don't listen for X connections. - // - - useUnixSocket = 0; - useTcpSocket = 0; - useAgentSocket = 0; - - // - // Get ready to open the local display. - // - - SetupDisplaySocket(xServerAddrFamily, xServerAddr, xServerAddrLength); - } - - // - // If we are the NX server-side proxy we need to - // complete our initializazion. We will mandate - // our parameters at the time the NX client will - // connect. - // - - if (control -> ProxyMode == proxy_client) - { - SetParameters(); - } - - return 1; -} - -int SetupProxyConnection() -{ - - if (proxyFD == -1) - { - - char *socketUri = NULL; - - // Let's make sure, the default value for listenSocket is properly set. Doing this - // here, because we have to make sure that we call it after the connectSocket - // declaration is really really complete. - - if (listenSocket.disabled() && connectSocket.disabled()) - { - char listenPortValue[20] = { 0 }; - sprintf(listenPortValue, "%ld", (long)(proxyPort + DEFAULT_NX_PROXY_PORT_OFFSET)); - - SetAndValidateChannelEndPointArg("local", "listen", listenPortValue, listenSocket); - } - - #ifdef TEST - connectSocket.getSpec(&socketUri); - *logofs << "Loop: connectSocket is "<< ( connectSocket.enabled() ? "enabled" : "disabled") << ". " - << "The socket URI is '"<< ( socketUri != NULL ? socketUri : "") << "'.\n" << logofs_flush; - listenSocket.getSpec(&socketUri); - *logofs << "Loop: listenSocket is "<< ( listenSocket.enabled() ? "enabled" : "disabled") << ". " - << "The socket URI is '"<< ( socketUri != NULL ? socketUri : "") << "'.\n" << logofs_flush; - free(socketUri); - socketUri = NULL; - #endif - - if (WE_INITIATE_CONNECTION) - { - if (connectSocket.getSpec(&socketUri)) - { - #ifdef TEST - *logofs << "Loop: Going to connect to '" << socketUri - << "'.\n" << logofs_flush; - #endif - free(socketUri); - - proxyFD = ConnectToRemote(connectSocket); - - #ifdef TEST - *logofs << "Loop: Connected to remote proxy on FD#" - << proxyFD << ".\n" << logofs_flush; - #endif - - cerr << "Info" << ": Connected to remote proxy on FD#" - << proxyFD << ".\n"; - } - } - else - { - - if (listenSocket.isTCPSocket() && (listenSocket.getTCPPort() < 0)) - { - listenSocket.setSpec(DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort); - } - - if (listenSocket.getSpec(&socketUri)) - { - #ifdef TEST - *logofs << "Loop: Going to wait for connection at '" - << socketUri << "'.\n" << logofs_flush; - #endif - free(socketUri); - - proxyFD = WaitForRemote(listenSocket); - - #ifdef TEST - if (WE_LISTEN_FORWARDER) - { - *logofs << "Loop: Connected to remote forwarder on FD#" - << proxyFD << ".\n" << logofs_flush; - } - else - { - *logofs << "Loop: Connected to remote proxy on FD#" - << proxyFD << ".\n" << logofs_flush; - } - #endif - - } - } - } - #ifdef TEST - else - { - *logofs << "Loop: Using the inherited connection on FD#" - << proxyFD << ".\n" << logofs_flush; - } - #endif - - // - // Set TCP_NODELAY on proxy descriptor - // to reduce startup time. Option will - // later be disabled if needed. - // - // either listenSocket or connectSocket is used here... - - if(listenSocket.isTCPSocket() || connectSocket.isTCPSocket()) - - SetNoDelay(proxyFD, 1); - - // - // We need non-blocking input since the - // negotiation phase. - // - - SetNonBlocking(proxyFD, 1); - - return 1; -} - -// -// Create the required proxy and channel classes -// and get ready for handling the encoded traffic. -// - -int InitAfterNegotiation() -{ - #ifdef TEST - *logofs << "Loop: Connection with remote proxy completed.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Connection with remote proxy completed.\n" - << logofs_flush; - - // - // If we are the server proxy we completed - // our initializazion phase according to - // the values provided by the client side. - // - - if (control -> ProxyMode == proxy_server) - { - SetParameters(); - } - - // - // Set up the listeners for the additional - // services. - // - - SetupServiceSockets(); - - // - // Create the proxy class and the statistics - // repository and pass all the configuration - // data we negotiated with the remote peer. - // - - SetupProxyInstance(); - - // - // We completed both parsing of user's parameters - // and handlshaking with remote proxy. Now print - // a brief summary including the most significant - // control values. - // - - PrintConnectionInfo(); - - // - // Cancel the initialization watchdog. - // - - if (IsRunning(lastWatchdog)) - { - KillProcess(lastWatchdog, "watchdog", SIGTERM, 1); - - SetNotRunning(lastWatchdog); - - lastSignal = 0; - } - - // - // Start the house-keeper process. It will - // remove the oldest persistent caches, if - // the amount of storage exceed the limits - // set by the user. - // - - StartKeeper(); - - // - // Set the log size check timestamp. - // - - nowTs = getNewTimestamp(); - - logsTs = nowTs; - - // - // TODO: Due to the way the new NX transport is working, - // the accounting of time spent handling messages must - // be rewritten. In particular, at the moment it only - // shows the time spent encoding and decoding messages - // in the main loop, after executing a select. It doesn't - // take into account the time spent in the NXTrans* calls - // where messages can be encoded and decoded implicitly, - // on demand of the agent. When the agent transport is - // in use, these calls constitute the vast majority of - // the encoding activity. The result is that the number - // of KB encoded per second shown by the proxy statistics - // is actually much lower than the real throughput gene- - // rated by the proxy. - // - - #ifdef TEST - *logofs << "Loop: INIT! Completed initialization at " - << strMsTimestamp(nowTs) << " with " - << diffTimestamp(initTs, nowTs) << " Ms " - << "since the init mark.\n" << logofs_flush; - #endif - - initTs = getNewTimestamp(); - - // - // We can now start handling binary data from - // our peer proxy. - // - - if (agent == NULL) - { - cerr << "Session" << ": Session started at '" - << strTimestamp() << "'.\n"; - } - - return 1; -} - -int SetMode(int mode) -{ - // - // Set the local proxy mode. - // - - if (control -> ProxyMode == proxy_undefined) - { - if (mode == NX_MODE_CLIENT) - { - #ifdef TEST - *logofs << "Loop: INIT! Initializing with mode " - << "NX_MODE_CLIENT at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - control -> ProxyMode = proxy_client; - } - else if (mode == NX_MODE_SERVER) - { - #ifdef TEST - *logofs << "Loop: INIT! Initializing with mode " - << "NX_MODE_SERVER at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - control -> ProxyMode = proxy_server; - } - else - { - cerr << "Error" << ": Please specify either " - << "the -C or -S option.\n"; - - HandleCleanup(); - } - } - - return 1; -} - -int SetupProxyInstance() -{ - if (control -> ProxyMode == proxy_client) - { - proxy = new ClientProxy(proxyFD); - } - else - { - proxy = new ServerProxy(proxyFD); - } - - if (proxy == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX proxy.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX proxy.\n"; - - HandleCleanup(); - } - - // - // Create the statistics repository. - // - - statistics = new Statistics(proxy); - - if (statistics == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX statistics.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX statistics.\n"; - - HandleCleanup(); - } - - // - // If user gave us a proxy cookie than create the - // X11 authorization repository and find the real - // cookie to be used for our X display. - // - - SetupAuthInstance(); - - // - // Reset the static members in channels. - // - - proxy -> handleChannelConfiguration(); - - // - // Inform the proxies about the ports where they - // will have to forward the network connections. - // - - proxy -> handleDisplayConfiguration(displayHost, xServerAddrFamily, - xServerAddr, xServerAddrLength); - - proxy -> handlePortConfiguration(cupsPort, smbPort, mediaPort, - httpPort, fontPort); - - // - // We handed over the sockaddr structure we - // created when we set up the display socket - // to the proxy. - // - - xServerAddr = NULL; - - // - // Set socket options on proxy link, then propagate link - // configuration to proxy. This includes translating some - // control parameters in 'local' and 'remote'. Finally - // adjust cache parameters according to pack method and - // session type selected by user. - // - - if (proxy -> handleSocketConfiguration() < 0 || - proxy -> handleLinkConfiguration() < 0 || - proxy -> handleCacheConfiguration() < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error configuring the NX transport.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error configuring the NX transport.\n"; - - HandleCleanup(); - } - - // - // Load the message stores from the persistent - // cache. - // - - proxy -> handleLoad(load_if_first); - - // - // Inform the proxy that from now on it can - // start handling the encoded data. - // - - proxy -> setOperational(); - - // - // Are we going to use an internal IPC connection - // with an agent? In this case create the channel - // by using the socket descriptor provided by the - // caller at the proxy initialization. - // - - SetupAgentInstance(); - - // - // Check if we need to verify the existence of - // a matching client cache at shutdown. - // - - #ifdef MATCH - - control -> PersistentCacheCheckOnShutdown = 1; - - #endif - - // - // Flush any data produced so far. - // - - proxy -> handleFlush(); - - #if defined(TEST) || defined(INFO) - - if (proxy -> getFlushable(proxyFD) > 0) - { - *logofs << "Loop: WARNING! Proxy FD#" << proxyFD << " has data " - << "to flush after setup of the NX transport.\n" - << logofs_flush; - } - - #endif - - return 1; -} - -int SetupAuthInstance() -{ - // - // If user gave us a proxy cookie, then create the - // X11 authorization repository and find the real - // cookie to be used for our X display. - // - - if (control -> ProxyMode == proxy_server) - { - if (authCookie != NULL && *authCookie != '\0') - { - if (useLaunchdSocket == 1) - { - // - // If we are going to retrieve the X11 autho- - // rization through the launchd service, make - // a connection to its socket to trigger the - // X server starting. - // - - sockaddr_un launchdAddrUnix; - - unsigned int launchdAddrLength = sizeof(sockaddr_un); - - int launchdAddrFamily = AF_UNIX; - - launchdAddrUnix.sun_family = AF_UNIX; - - const int launchdAddrNameLength = 108; - - int success = -1; - - strncpy(launchdAddrUnix.sun_path, displayHost, launchdAddrNameLength); - - *(launchdAddrUnix.sun_path + launchdAddrNameLength - 1) = '\0'; - - #ifdef TEST - *logofs << "Loop: Connecting to launchd service " - << "on Unix port '" << displayHost << "'.\n" << logofs_flush; - #endif - - int launchdFd = socket(launchdAddrFamily, SOCK_STREAM, PF_UNSPEC); - - if (launchdFd < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to socket failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - } - else if ((success = connect(launchdFd, (sockaddr *) &launchdAddrUnix, launchdAddrLength)) < 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Connection to launchd service " - << "on Unix port '" << displayHost << "' failed " - << "with error " << EGET() << ", '" << ESTR() << "'.\n" - << logofs_flush; - #endif - } - - if (launchdFd >= 0) - { - close(launchdFd); - } - - // - // The real cookie will not be available - // until the X server starts. Query for the - // cookie in a loop, unless the connection - // to the launchd service failed. - // - - int attempts = (success < 0 ? 1 : 10); - - for (int i = 0; i < attempts; i++) - { - delete auth; - - auth = new Auth(displayHost, authCookie); - - if (auth != NULL && auth -> isFake() == 1) - { - usleep(200000); - - continue; - } - - break; - } - } - else - { - auth = new Auth(displayHost, authCookie); - } - - if (auth == NULL || auth -> isValid() != 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the X authorization.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the X authorization.\n"; - - HandleCleanup(); - } - else if (auth -> isFake() == 1) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Could not retrieve the X server " - << "authentication cookie.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Failed to read data from the X " - << "auth command.\n"; - - cerr << "Warning" << ": Generated a fake cookie for X " - << "authentication.\n"; - } - } - else - { - #ifdef TEST - *logofs << "Loop: No proxy cookie was provided for " - << "authentication.\n" << logofs_flush; - #endif - - cerr << "Info" << ": No proxy cookie was provided for " - << "authentication.\n"; - - #ifdef TEST - *logofs << "Loop: Forwarding the real X authorization " - << "cookie.\n" << logofs_flush; - #endif - - cerr << "Info" << ": Forwarding the real X authorization " - << "cookie.\n"; - } - } - - return 1; -} - -int SetupAgentInstance() -{ - if (control -> ProxyMode == proxy_client && - useAgentSocket == 1) - { - // - // This will temporarily disable signals to safely - // load the cache, then will send a control packet - // to the remote end, telling that cache has to be - // loaded, so it's important that proxy is already - // set in operational state. - // - - int result; - - if (agent != NULL) - { - result = proxy -> handleNewAgentConnection(agent); - } - else - { - result = proxy -> handleNewConnection(channel_x11, agentFD[1]); - } - - if (result < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating the NX agent connection.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error creating the NX agent connection.\n"; - - HandleCleanup(); - } - } - - return 1; -} - -int SetupTcpSocket() -{ - // - // Open TCP socket emulating local display. - // - - return ListenConnectionTCP((loopbackBind ? "localhost" : "*"), X_TCP_PORT + proxyPort, "X11"); -} - -int SetupUnixSocket() -{ - // - // Open UNIX domain socket for display. - // - - if (!control->TempPath) { - #ifdef PANIC - *logofs << "Loop: PANIC! Temporal path is null.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Temporal path is null.\n"; - HandleCleanup(); - } - - unsigned int required = snprintf(unixSocketName, DEFAULT_STRING_LENGTH, "%s/.X11-unix", control->TempPath); - if (required < sizeof(unixSocketName)) { - - // No need to execute the following actions conditionally - mkdir(unixSocketName, (0777 | S_ISVTX)); - chmod(unixSocketName, (0777 | S_ISVTX)); - - required = snprintf(unixSocketName, DEFAULT_STRING_LENGTH, "%s/.X11-unix/X%d", control->TempPath, proxyPort); - if (required < sizeof(unixSocketName)) { - - unixFD = ListenConnectionUnix(unixSocketName, "x11"); - if (unixFD >= 0) - chmod(unixSocketName, 0777); - return unixFD; - } - } - - unixSocketName[0] = '\0'; // Just in case! - - #ifdef PANIC - *logofs << "Loop: PANIC! path for unix socket is too long.\n" << logofs_flush; - #endif - - cerr << "Error" << ": path for Unix socket is too long.\n"; - HandleCleanup(); -} - -// -// The following is a dumb copy-paste. The -// nxcompsh library should offer a better -// implementation. -// - -int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr, - unsigned int &xServerAddrLength) -{ - xServerAddrFamily = AF_INET; - xServerAddr = NULL; - xServerAddrLength = 0; - - char *display; - - if (*displayHost == '\0') - { - // - // Assume DISPLAY as the X server to which - // we will forward the proxied connections. - // This means that NX parameters have been - // passed through other means. - // - - display = getenv("DISPLAY"); - - if (display == NULL || *display == '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! Host X server DISPLAY is not set.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Host X server DISPLAY is not set.\n"; - - HandleCleanup(); - } - else if (strncasecmp(display, "nx/nx,", 6) == 0 || - strncasecmp(display, "nx,", 3) == 0 || - strncasecmp(display, "nx/nx:", 6) == 0 || - strncasecmp(display, "nx:", 3) == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! NX transport on host X server '" - << display << "' not supported.\n" << logofs_flush; - #endif - - cerr << "Error" << ": NX transport on host X server '" - << display << "' not supported.\n"; - - cerr << "Error" << ": Please run the local proxy specifying " - << "the host X server to connect to.\n"; - - HandleCleanup(); - } - else if (strlen(display) >= DEFAULT_STRING_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Host X server DISPLAY cannot exceed " - << DEFAULT_STRING_LENGTH << " characters.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Host X server DISPLAY cannot exceed " - << DEFAULT_STRING_LENGTH << " characters.\n"; - - HandleCleanup(); - } - - strcpy(displayHost, display); - } - - display = new char[strlen(displayHost) + 1]; - - if (display == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Out of memory handling DISPLAY variable.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Out of memory handling DISPLAY variable.\n"; - - HandleCleanup(); - } - - strcpy(display, displayHost); - - #ifdef __APPLE__ - - if ((strncasecmp(display, "/tmp/launch", 11) == 0) || (strncasecmp(display, "/private/tmp/com.apple.launchd", 30) == 0)) - { - #ifdef TEST - *logofs << "Loop: Using launchd service on socket '" - << display << "'.\n" << logofs_flush; - #endif - - useLaunchdSocket = 1; - } - - #endif - - char *separator = strrchr(display, ':'); - - if ((separator == NULL) || !isdigit(*(separator + 1))) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid display '" << display << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid display '" << display << "'.\n"; - - HandleCleanup(); - } - - *separator = '\0'; - - xPort = atoi(separator + 1); - - #ifdef TEST - *logofs << "Loop: Using local X display '" << displayHost - << "' with host '" << display << "' and port '" - << xPort << "'.\n" << logofs_flush; - #endif - - #ifdef __APPLE__ - - if (separator == display || strcmp(display, "unix") == 0 || - useLaunchdSocket == 1) - - #else - - if (separator == display || strcmp(display, "unix") == 0) - - #endif - { - // - // UNIX domain port. - // - - #ifdef TEST - *logofs << "Loop: Using real X server on UNIX domain socket.\n" - << logofs_flush; - #endif - - sockaddr_un *xServerAddrUNIX = new sockaddr_un; - - xServerAddrFamily = AF_UNIX; - xServerAddrUNIX -> sun_family = AF_UNIX; - - // - // The scope of this function is to fill either the sockaddr_un - // (when the display is set to the Unix Domain socket) or the - // sockaddr_in structure (when connecting by TCP) only once, so - // that the structure will be later used at the time the server - // proxy will try to forward the connection to the X server. We - // don't need to verify that the socket does exist at the pre- - // sent moment. The method that forwards the connection will - // perform the required checks and will retry, if needed. Anyway - // we need to select the name of the socket, so we check if the - // well-known directory exists and take that as an indication of - // where the socket will be created. - // - - // Try abstract X11 socket first (via a test connect), if that fails - // fall back to Unix domain socket file. - - #ifdef __linux__ - int testSocketFD; - testSocketFD = socket(xServerAddrFamily, SOCK_STREAM, PF_UNSPEC); - - int len = sprintf(unixSocketName + 1, "/tmp/.X11-unix/X%d", xPort); - unixSocketName[0] = '\0'; - - sockaddr_un *xServerAddrABSTRACT = new sockaddr_un; - memset(xServerAddrABSTRACT, 0, xServerAddrLength); - xServerAddrABSTRACT -> sun_family = AF_UNIX; - memcpy(xServerAddrABSTRACT -> sun_path, unixSocketName, len+1); - xServerAddrLength = len +3; - - int ret = connect(testSocketFD, (struct sockaddr *) xServerAddrABSTRACT, xServerAddrLength); - if (ret == 0) { - - cerr << "Info" << ": Using abstract X11 socket in kernel namespace " - << "for accessing DISPLAY=:" << xPort << ".\n"; - - close(testSocketFD); - xServerAddr = (sockaddr *) xServerAddrABSTRACT; - return 1; - - } else { - - cerr << "Info" << ": Falling back to file system X11 socket " - << "for accessing DISPLAY=:" << xPort << ".\n"; - - #endif - - struct stat statInfo; - - char unixSocketDir[DEFAULT_STRING_LENGTH]; - - snprintf(unixSocketDir, DEFAULT_STRING_LENGTH - 1, "%s/.X11-unix", - control -> TempPath); - - #ifdef __APPLE__ - - if (useLaunchdSocket == 1) - { - char *slash = rindex(display, '/'); - - if (slash != NULL) - { - *slash = '\0'; - } - - snprintf(unixSocketDir, DEFAULT_STRING_LENGTH - 1, "%s", display); - } - - #endif - - *(unixSocketDir + DEFAULT_STRING_LENGTH - 1) = '\0'; - - #ifdef TEST - *logofs << "Loop: Assuming X socket in directory '" - << unixSocketDir << "'.\n" << logofs_flush; - #endif - - if (stat(unixSocketDir, &statInfo) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't determine the location of " - << "the X display socket.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't determine the location of " - << "the X display socket.\n"; - - #ifdef PANIC - *logofs << "Loop: PANIC! Error " << EGET() << " '" << ESTR() - << "' checking '" << unixSocketDir << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error " << EGET() << " '" << ESTR() - << "' checking '" << unixSocketDir << "'.\n"; - - HandleCleanup(); - } - - sprintf(unixSocketName, "%s/X%d", unixSocketDir, xPort); - - #ifdef __APPLE__ - - if (useLaunchdSocket == 1) - { - strncpy(unixSocketName, displayHost, DEFAULT_STRING_LENGTH - 1); - } - - #endif - - #ifdef TEST - *logofs << "Loop: Assuming X socket name '" << unixSocketName - << "'.\n" << logofs_flush; - #endif - - strcpy(xServerAddrUNIX -> sun_path, unixSocketName); - - xServerAddr = (sockaddr *) xServerAddrUNIX; - xServerAddrLength = sizeof(sockaddr_un); - - #ifdef __linux__ - - } - #endif - } - else - { - // - // TCP port. - // - - #ifdef TEST - *logofs << "Loop: Using real X server on TCP port.\n" - << logofs_flush; - #endif - - xServerAddrFamily = AF_INET; - - int xServerIPAddr = GetHostAddress(display); - - if (xServerIPAddr == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unknown display host '" << display - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unknown display host '" << display - << "'.\n"; - - HandleCleanup(); - } - - sockaddr_in *xServerAddrTCP = new sockaddr_in; - - xServerAddrTCP -> sin_family = AF_INET; - xServerAddrTCP -> sin_port = htons(X_TCP_PORT + xPort); - xServerAddrTCP -> sin_addr.s_addr = xServerIPAddr; - - xServerAddr = (sockaddr *) xServerAddrTCP; - xServerAddrLength = sizeof(sockaddr_in); - } - - delete [] display; - - return 1; -} - -int SetupServiceSockets() -{ - if (control -> ProxyMode == proxy_client) - { - if (useCupsSocket) - { - if ((cupsFD = ListenConnection(cupsPort, "CUPS")) < 0) - { - useCupsSocket = 0; - } - } - - if (useAuxSocket) - { - if ((auxFD = ListenConnection(auxPort, "auxiliary X11")) < 0) - { - useAuxSocket = 0; - } - } - - if (useSmbSocket) - { - if ((smbFD = ListenConnection(smbPort, "SMB")) < 0) - { - useSmbSocket = 0; - } - } - - if (useMediaSocket) - { - if ((mediaFD = ListenConnection(mediaPort, "media")) < 0) - { - useMediaSocket = 0; - } - } - - if (useHttpSocket) - { - if ((httpFD = ListenConnection(httpPort, "http")) < 0) - { - useHttpSocket = 0; - } - } - - useFontSocket = 0; - } - else - { - // - // Get ready to listen for the font server connections - // - - if (useFontSocket) - { - // Since ProtoStep7 (#issue 108) - int port = atoi(fontPort); - - if ((fontFD = ListenConnectionTCP("localhost", port, "font")) < 0) - { - useFontSocket = 0; - } - } - - useCupsSocket = 0; - useAuxSocket = 0; - useSmbSocket = 0; - useMediaSocket = 0; - useHttpSocket = 0; - } - - // - // Slave channels can be originated - // by both sides. - // - - if (useSlaveSocket) - { - // Since ProtoStep7 (#issue 108) - if ((slaveFD = ListenConnection(slavePort, "slave")) < 0) - { - useSlaveSocket = 0; - } - } - - return 1; -} - -int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label) -{ - int newFD = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC); - - if (newFD == -1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to socket failed for " << label - << " socket. Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to socket failed for " << label - << " socket. Error is " << EGET() << " '" - << ESTR() << "'.\n"; - - goto SetupSocketError; - } - - if (addr->sa_family == AF_INET) - if (SetReuseAddress(newFD) < 0) - { - // SetReuseAddress already warns with an error - goto SetupSocketError; - } - - if (bind(newFD, addr, addrlen) == -1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to bind failed for " << label - << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to bind failed for " << label - << ". Error is " << EGET() - << " '" << ESTR() << "'.\n"; - goto SetupSocketError; - } - - if (listen(newFD, 8) == -1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to listen failed for " << label - << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to listen failed for " << label - << ". Error is " << EGET() - << " '" << ESTR() << "'.\n"; - - goto SetupSocketError; - } - - return newFD; - -SetupSocketError: - - if (newFD != -1) - { - close(newFD); - } - - // - // May optionally return. The session would - // continue without the service. The problem - // with this approach is that it would make - // harder to track problems with allocation - // of ports in clients and server. - // - - HandleCleanup(); - return -1; -} - -int ListenConnectionUnix(const char *path, const char *label) -{ - - sockaddr_un unixAddr; - unixAddr.sun_family = AF_UNIX; -#ifdef UNIX_PATH_MAX - if (strlen(path) >= UNIX_PATH_MAX) -#else - if (strlen(path) >= sizeof(unixAddr.sun_path)) -#endif - { - #ifdef PANIC - *logofs << "Loop: PANIC! Socket path \"" << path << "\" for " - << label << " is too long.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Socket path \"" << path << "\" for " - << label << " is too long.\n"; - - HandleCleanup(); - return -1; - } - - strcpy(unixAddr.sun_path, path); - return ListenConnectionAny((sockaddr *)&unixAddr, sizeof(unixAddr), label); -} - -int ListenConnectionTCP(const char *host, long port, const char *label) -{ - sockaddr_in tcpAddr; - tcpAddr.sin_family = AF_INET; - tcpAddr.sin_port = htons(port); - - if (loopbackBind || - !host || - !strcmp(host, "") || - !strcmp(host, "localhost")) { - tcpAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - } - else if(strcmp(host, "*") == 0) { - tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY); - } - else { - int ip = tcpAddr.sin_addr.s_addr = GetHostAddress(host); - if (ip == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unknown " << label << " host '" << host - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unknown " << label << " host '" << host - << "'.\n"; - - HandleCleanup(); - return -1; - } - } - - return ListenConnectionAny((sockaddr *)&tcpAddr, sizeof(tcpAddr), label); -} - -int ListenConnection(ChannelEndPoint &endpoint, const char *label) -{ - char *unixPath, *host; - long port; - if (endpoint.getUnixPath(&unixPath)) { - return ListenConnectionUnix(unixPath, label); - } - else if (endpoint.getTCPHostAndPort(&host, &port)) { - return ListenConnectionTCP(host, port, label); - } - return -1; -} - -static int AcceptConnection(int fd, int domain, const char *label) -{ - struct sockaddr newAddr; - - socklen_t addrLen = sizeof(newAddr); - - #ifdef TEST - - if (domain == AF_UNIX) - { - *logofs << "Loop: Going to accept new Unix " << label - << " connection on FD#" << fd << ".\n" - << logofs_flush; - } - else - { - *logofs << "Loop: Going to accept new TCP " << label - << " connection on FD#" << fd << ".\n" - << logofs_flush; - } - - #endif - - int newFD = accept(fd, &newAddr, &addrLen); - - if (newFD < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to accept failed for " - << label << " connection. Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to accept failed for " - << label << " connection. Error is " << EGET() - << " '" << ESTR() << "'.\n"; - } - - return newFD; -} - -void HandleShutdown() -{ - if (proxy -> getShutdown() == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! No shutdown of proxy link " - << "performed by remote proxy.\n" - << logofs_flush; - #endif - - // - // Close the socket before showing the alert. - // It seems that the closure of the socket can - // sometimes take several seconds, even after - // the connection is broken. The result is that - // the dialog can be shown long after the user - // has gone after the failed session. Note that - // disabling the linger timeout does not seem - // to make any difference. - // - - CleanupSockets(); - - cerr << "Error" << ": Connection with remote peer broken.\n"; - - #ifdef TEST - *logofs << "Loop: Bytes received so far are " - << (unsigned long long) statistics -> getBytesIn() - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Please check the state of your " - << "network and retry.\n"; - - handleTerminatingInLoop(); - - if (control -> ProxyMode == proxy_server) - { - #ifdef TEST - *logofs << "Loop: Showing the proxy abort dialog.\n" - << logofs_flush; - #endif - - HandleAlert(ABORT_PROXY_CONNECTION_ALERT, 1); - - handleAlertInLoop(); - } - } - #ifdef TEST - else - { - *logofs << "Loop: Finalized the remote proxy shutdown.\n" - << logofs_flush; - } - #endif - - HandleCleanup(); -} - - -void WaitCleanup() -{ - T_timestamp selectTs; - - while (NXTransRunning(NX_FD_ANY)) - { - setTimestamp(selectTs, control -> PingTimeout); - - NXTransContinue(&selectTs); - } -} - -int KillProcess(int pid, const char *label, int signal, int wait) -{ - if (pid > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Killing the " << label << " process '" - << pid << "' from process with pid '" << getpid() - << "' with signal '" << DumpSignal(signal) - << "'.\n" << logofs_flush; - #endif - - signal = (signal == 0 ? SIGTERM : signal); - - if (kill(pid, signal) < 0 && EGET() != ESRCH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Couldn't kill the " << label - << " process with pid '" << pid << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Couldn't kill the " << label - << " process with pid '" << pid << "'.\n"; - } - - if (wait == 1) - { - WaitChild(pid, label, 1); - } - - return 1; - } - else - { - #ifdef TEST - *logofs << "Loop: No " << label << " process " - << "to kill with pid '" << pid - << "'.\n" << logofs_flush; - #endif - - return 0; - } -} - -int CheckProcess(int pid, const char *label) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Checking the " << label << " process '" - << pid << "' from process with pid '" << getpid() - << "'.\n" << logofs_flush; - #endif - - if (kill(pid, SIGCONT) < 0 && EGET() == ESRCH) - { - #ifdef WARNING - *logofs << "Loop: WARNING! The " << label << " process " - << "with pid '" << pid << "' has exited.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": The " << label << " process " - << "with pid '" << pid << "' has exited.\n"; - - return 0; - } - - return 1; -} - -int StartKeeper() -{ - #if defined(TEST) || defined(INFO) - - if (IsRunning(lastKeeper) == 1 || - IsRestarting(lastKeeper) == 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! The house-keeping process is " - << "alreay running with pid '" << lastKeeper - << "'.\n" << logofs_flush; - #endif - - HandleCleanup(); - } - - #endif - - // - // Don't care harvesting the persistent caches if - // the memory cache is not enabled. If the memory - // cache is not enabled neither we produced per- - // sistent caches. The user can still delete any - // persistent cache produced by the previous runs - // by using the client GUI. - // - // TODO: At the moment the user doesn't have a way - // to specify the amount of disk space to use for - // the persistent caches, but only the amount of - // space to use for images. - // - - if (control -> LocalTotalStorageSize > 0) - { - #ifdef TEST - *logofs << "Loop: Starting the house-keeping process with " - << "storage size " << control -> PersistentCacheDiskLimit - << ".\n" << logofs_flush; - #endif - - lastKeeper = NXTransKeeper(control -> PersistentCacheDiskLimit, - 0, control -> RootPath); - - if (IsFailed(lastKeeper)) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Failed to start the NX keeper process.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Failed to start the NX keeper process.\n"; - - SetNotRunning(lastKeeper); - } - #ifdef TEST - else - { - *logofs << "Loop: Keeper started with pid '" - << lastKeeper << "'.\n" << logofs_flush; - } - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Nothing to do for the keeper process " - << "with persistent cache not enabled.\n" - << logofs_flush; - } - #endif - - return 1; -} - -void HandleCleanupForReconnect() -{ - #ifdef TEST - *logofs << "Loop: Going to clean up system resources for Reconnect " - << "in process '" << getpid() << "'.\n" - << logofs_flush; - #endif - handleTerminatedInLoop(); - DisableSignals(); - if (control) - CleanupChildren(); - CleanupListeners(); - CleanupSockets(); - CleanupKeeper(); - CleanupStreams(); - CleanupLocal(); - CleanupGlobal(); - RestoreSignals(); - ServerCache::lastInitReply.set(0,NULL); - ServerCache::lastKeymap.set(0,NULL); - ServerCache::getKeyboardMappingLastMap.set(0,NULL); -} -void HandleCleanup(int code) -{ - #ifdef TEST - *logofs << "Loop: Going to clean up system resources " - << "in process '" << getpid() << "'.\n" - << logofs_flush; - #endif - - handleTerminatedInLoop(); - - // - // Suspend any signal while cleaning up. - // - - DisableSignals(); - - if (getpid() == lastProxy) - { - // - // Terminate all the children. - // - - CleanupChildren(); - - // - // Close all listeners. - // - - CleanupListeners(); - - // - // Close all sockets. - // - - CleanupSockets(); - - // - // Release the global objects. - // - - CleanupGlobal(); - - // - // Restore the original signal handlers. - // - - RestoreSignals(); - } - - // - // This is our last chance to print a message. If this - // is the process which created the transport we will - // jump back into the loop, letting the caller find out - // that the connection is broken, otherwise we assume - // that this is a child of the proxy and so we will - // safely exit. - // - - #ifdef TEST - - if (getpid() == lastProxy) - { - *logofs << "Loop: Reverting to loop context in process with " - << "pid '" << getpid() << "' at " << strMsTimestamp() - << ".\n" << logofs_flush; - } - else - { - *logofs << "Loop: Exiting from child process with pid '" - << getpid() << "' at " << strMsTimestamp() - << ".\n" << logofs_flush; - } - - #endif - - if (getpid() == lastProxy) - { - // - // Reset all values to their default. - // - - CleanupLocal(); - - CleanupStreams(); - - longjmp(context, 1); - } - else - { - // - // Give a last chance to the process - // to cleanup the ancillary classes. - // - - CleanupKeeper(); - - CleanupStreams(); - - exit(code); - } -} - -void CleanupKeeper() -{ - if (keeper != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up keeper in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete keeper; - - keeper = NULL; - } -} - -void CleanupStreams() -{ - // - // TODO: The cleanup procedure skips deletion of - // the I/O streams under Windows. This is intended - // to avoid a strange segfault occurring randomly, - // at the time the proxy is being shut down. - // - - #ifndef __CYGWIN32__ - - #ifdef TEST - *logofs << "Loop: Freeing up streams in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if (logofs != NULL && logofs != &cerr && - *errorsFileName != '\0') - { - *logofs << flush; - - delete logofs; - - // - // Let the log go again to the standard - // error. - // - - logofs = &cerr; - } - - if (statofs != NULL && statofs != &cerr && - *statsFileName != '\0') - { - *statofs << flush; - - delete statofs; - - statofs = NULL; - } - - if (errofs != NULL) - { - *errofs << flush; - - if (errofs == &cerr) - { - errofs = NULL; - } - else if (errsbuf != NULL) - { - cerr.rdbuf(errsbuf); - - errsbuf = NULL; - - delete errofs; - } - - errofs = NULL; - } - - #endif /* #ifndef __CYGWIN32__ */ - - // - // Reset these as they can't be reset - // in CleanupLocal(). - // - - *sessionFileName = '\0'; - *errorsFileName = '\0'; - *optionsFileName = '\0'; - *statsFileName = '\0'; -} - -void CleanupChildren() -{ - // - // Remove any watchdog. - // - - if (IsRunning(lastWatchdog)) - { - KillProcess(lastWatchdog, "watchdog", SIGTERM, 1); - - SetNotRunning(lastWatchdog); - - lastSignal = 0; - } - - // - // Kill the cache house-keeping process. - // - - if (IsRunning(lastKeeper)) - { - KillProcess(lastKeeper, "house-keeping", SIGTERM, 1); - - SetNotRunning(lastKeeper); - } - - // - // Let any running dialog to continue until it is - // closed by the user. In general this is the exp- - // ected behaviour, as for example when we are - // exiting because the link was abrouptedly shut - // down. - // - - if (IsRunning(lastDialog)) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: WARNING! Leaving the dialog process '" - << lastDialog << "' running in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - SetNotRunning(lastDialog); - } - - // - // Give user a chance to start a new session. - // - - if (control -> EnableRestartOnShutdown == 1) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Respawning the NX client " - << "on display '" << displayHost << "'.\n" - << logofs_flush; - #endif - - NXTransClient(displayHost); - } - - for (int i = 0; i < control -> KillDaemonOnShutdownNumber; i++) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Killing the NX daemon with " - << "pid '" << control -> KillDaemonOnShutdown[i] - << "'.\n" << logofs_flush; - #endif - - KillProcess(control -> KillDaemonOnShutdown[i], "daemon", SIGTERM, 0); - } -} - -void CleanupGlobal() -{ - if (proxy != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up proxy in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete proxy; - - proxy = NULL; - } - - if (agent != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up agent in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete agent; - - agent = NULL; - } - - if (auth != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up auth data in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete auth; - - auth = NULL; - } - - if (statistics != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up statistics in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete statistics; - - statistics = NULL; - } - - if (control != NULL) - { - #ifdef TEST - *logofs << "Loop: Freeing up control in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - delete control; - - control = NULL; - } -} - -void CleanupConnections() -{ - if (proxy -> getChannels(channel_x11) != 0) - { - #ifdef TEST - *logofs << "Loop: Closing any remaining X connections.\n" - << logofs_flush; - #endif - - proxy -> handleCloseAllXConnections(); - - #ifdef TEST - *logofs << "Loop: Closing any remaining listener.\n" - << logofs_flush; - #endif - - proxy -> handleCloseAllListeners(); - } - - proxy -> handleFinish(); -} - -void CleanupListeners() -{ - if (useTcpSocket == 1) - { - if (tcpFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing TCP listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(tcpFD); - - tcpFD = -1; - } - - useTcpSocket = 0; - } - - if (useUnixSocket == 1) - { - if (unixFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing UNIX listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(unixFD); - - unixFD = -1; - } - - if (*unixSocketName != '\0') - { - #ifdef TEST - *logofs << "Loop: Going to remove the Unix domain socket '" - << unixSocketName << "' in process " << "with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - unlink(unixSocketName); - } - - useUnixSocket = 0; - } - - if (useAgentSocket == 1) - { - // - // There is no listener for the - // agent descriptor. - // - - useAgentSocket = 0; - } - - if (useCupsSocket == 1) - { - if (cupsFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing CUPS listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(cupsFD); - - cupsFD = -1; - } - - useCupsSocket = 0; - } - - if (useAuxSocket == 1) - { - if (auxFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing auxiliary X11 listener " - << "in process " << "with pid '" << getpid() - << "'.\n" << logofs_flush; - #endif - - close(auxFD); - - auxFD = -1; - } - - useAuxSocket = 0; - } - - if (useSmbSocket == 1) - { - if (smbFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing SMB listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(smbFD); - - smbFD = -1; - } - - useSmbSocket = 0; - } - - if (useMediaSocket == 1) - { - if (mediaFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing multimedia listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(mediaFD); - - mediaFD = -1; - } - - useMediaSocket = 0; - } - - if (useHttpSocket == 1) - { - if (httpFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing http listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(httpFD); - - httpFD = -1; - } - - useHttpSocket = 0; - } - - if (useFontSocket == 1) - { - if (fontFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing font server listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(fontFD); - - fontFD = -1; - } - - useFontSocket = 0; - } - - if (useSlaveSocket == 1) - { - if (slaveFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing slave listener in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(slaveFD); - - slaveFD = -1; - } - - useSlaveSocket = 0; - } -} - -void CleanupSockets() -{ - if (proxyFD != -1) - { - #ifdef TEST - *logofs << "Loop: Closing proxy FD in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(proxyFD); - - proxyFD = -1; - } - - if (agentFD[1] != -1) - { - #ifdef TEST - *logofs << "Loop: Closing agent FD in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - close(agentFD[1]); - - agentFD[0] = -1; - agentFD[1] = -1; - } -} - -void CleanupLocal() -{ - *homeDir = '\0'; - *rootDir = '\0'; - *tempDir = '\0'; - *systemDir = '\0'; - *sessionDir = '\0'; - - *linkSpeedName = '\0'; - *cacheSizeName = '\0'; - *shsegSizeName = '\0'; - *imagesSizeName = '\0'; - *bitrateLimitName = '\0'; - *packMethodName = '\0'; - *productName = '\0'; - - packMethod = -1; - packQuality = -1; - - *sessionType = '\0'; - *sessionId = '\0'; - - parsedOptions = 0; - parsedCommand = 0; - - *remoteData = '\0'; - remotePosition = 0; - - tcpFD = -1; - unixFD = -1; - cupsFD = -1; - auxFD = -1; - smbFD = -1; - mediaFD = -1; - httpFD = -1; - fontFD = -1; - slaveFD = -1; - proxyFD = -1; - - agentFD[0] = -1; - agentFD[1] = -1; - - useUnixSocket = 1; - useTcpSocket = 1; - useCupsSocket = 0; - useAuxSocket = 0; - useSmbSocket = 0; - useMediaSocket = 0; - useHttpSocket = 0; - useFontSocket = 0; - useSlaveSocket = 0; - useAgentSocket = 0; - - useNoDelay = -1; - usePolicy = -1; - useRender = -1; - useTaint = -1; - - *unixSocketName = '\0'; - - *acceptHost = '\0'; - *displayHost = '\0'; - *authCookie = '\0'; - - proxyPort = DEFAULT_NX_PROXY_PORT; - xPort = DEFAULT_NX_X_PORT; - - xServerAddrFamily = -1; - xServerAddrLength = 0; - - delete xServerAddr; - - xServerAddr = NULL; - - listenSocket.disable(); - connectSocket.disable(); - - cupsPort.disable(); - auxPort.disable(); - smbPort.disable(); - mediaPort.disable(); - httpPort.disable(); - slavePort.disable(); - - *fontPort = '\0'; - - *bindHost = '\0'; - bindPort = -1; - - initTs = nullTimestamp(); - startTs = nullTimestamp(); - logsTs = nullTimestamp(); - nowTs = nullTimestamp(); - - diffTs = 0; - - lastProxy = 0; - lastDialog = 0; - lastWatchdog = 0; - lastKeeper = 0; - lastStatus = 0; - lastKill = 0; - lastDestroy = 0; - - lastReadableTs = nullTimestamp(); - - lastAlert.code = 0; - lastAlert.local = 0; - - lastMasks.blocked = 0; - lastMasks.installed = 0; - - memset(&lastMasks.saved, 0, sizeof(sigset_t)); - - for (int i = 0; i < 32; i++) - { - lastMasks.enabled[i] = 0; - lastMasks.forward[i] = 0; - - memset(&lastMasks.action[i], 0, sizeof(struct sigaction)); - } - - lastSignal = 0; - - memset(&lastTimer.action, 0, sizeof(struct sigaction)); - memset(&lastTimer.value, 0, sizeof(struct itimerval)); - - lastTimer.start = nullTimestamp(); - lastTimer.next = nullTimestamp(); -} - -int CheckAbort() -{ - if (lastSignal != 0) - { - #ifdef TEST - *logofs << "Loop: Aborting the procedure due to signal '" - << lastSignal << "', '" << DumpSignal(lastSignal) - << "'.\n" << logofs_flush; - #endif - - cerr << "Info" << ": Aborting the procedure due to signal '" - << lastSignal << "'.\n"; - - lastSignal = 0; - - return 1; - } - - return 0; -} - -void HandleAbort() -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - *logofs << flush; - - handleTerminatingInLoop(); - - if (lastSignal == SIGHUP) - { - lastSignal = 0; - } - - // - // The current default is to just quit the program. - // Code has not been updated to deal with the new - // NX transport loop. - // - - if (control -> EnableCoreDumpOnAbort == 1) - { - if (agent != NULL) - { - cerr << "Session" << ": Terminating session at '" - << strTimestamp() << "'.\n"; - } - - cerr << "Error" << ": Generating a core file to help " - << "the investigations.\n"; - - cerr << "Session" << ": Session terminated at '" - << strTimestamp() << "'.\n"; - - cerr << flush; - - signal(SIGABRT, SIG_DFL); - - raise(SIGABRT); - } - - #ifdef TEST - *logofs << "Loop: Showing the proxy abort dialog.\n" - << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_server) - { - // - // Close the socket before showing the alert. - // It seems that the closure of the socket can - // sometimes take several seconds, even after - // the connection is broken. - // - - CleanupSockets(); - - if (lastKill == 0) - { - HandleAlert(ABORT_PROXY_CONNECTION_ALERT, 1); - } - else - { - HandleAlert(ABORT_PROXY_SHUTDOWN_ALERT, 1); - } - - handleAlertInLoop(); - } - - HandleCleanup(); -} - -void HandleAlert(int code, int local) -{ - if (lastAlert.code == 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Requesting an alert dialog with code " - << code << " and local " << local << ".\n" - << logofs_flush; - #endif - - lastAlert.code = code; - lastAlert.local = local; - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "Loop: WARNING! Alert dialog already requested " - << "with code " << lastAlert.code << ".\n" - << logofs_flush; - } - #endif - - return; -} - -void FlushCallback(int length) -{ - if (flushCallback != NULL) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Reporting a flush request at " - << strMsTimestamp() << " with " << length - << " bytes written.\n" << logofs_flush; - #endif - - (*flushCallback)(flushParameter, length); - } - #if defined(TEST) || defined(INFO) - else if (control -> ProxyMode == proxy_client) - { - *logofs << "Loop: WARNING! Can't find a flush " - << "callback in process with pid '" << getpid() - << "'.\n" << logofs_flush; - } - #endif -} - -void KeeperCallback() -{ - if (IsRunning(lastKeeper) == 0) - { - // - // Let the house-keeping process take care - // of the persistent image cache. - // - - if (control -> ImageCacheEnableLoad == 1 || - control -> ImageCacheEnableSave == 1) - { - #ifdef TEST - *logofs << "Loop: Starting the house-keeping process with " - << "image storage size " << control -> ImageCacheDiskLimit - << ".\n" << logofs_flush; - #endif - - lastKeeper = NXTransKeeper(0, control -> ImageCacheDiskLimit, - control -> RootPath); - - if (IsFailed(lastKeeper)) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Can't start the NX keeper process.\n" - << logofs_flush; - #endif - - SetNotRunning(lastKeeper); - } - #ifdef TEST - else - { - *logofs << "Loop: Keeper started with pid '" - << lastKeeper << "'.\n" << logofs_flush; - } - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Nothing to do for the keeper process " - << "with image cache not enabled.\n" - << logofs_flush; - } - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Nothing to do with the keeper process " - << "already running.\n" << logofs_flush; - } - #endif -} - -void InstallSignals() -{ - #ifdef TEST - *logofs << "Loop: Installing signals in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - for (int i = 0; i < 32; i++) - { - if (CheckSignal(i) == 1 && - lastMasks.enabled[i] == 0) - { - InstallSignal(i, NX_SIGNAL_ENABLE); - } - } - - lastMasks.installed = 1; -} - -void RestoreSignals() -{ - #ifdef TEST - *logofs << "Loop: Restoring signals in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - if (lastMasks.installed == 1) - { - // - // Need to keep monitoring the children. - // - - for (int i = 0; i < 32; i++) - { - if (lastMasks.enabled[i] == 1) - { - RestoreSignal(i); - } - } - } - - lastMasks.installed = 0; - - if (lastMasks.blocked == 1) - { - EnableSignals(); - } -} - -void DisableSignals() -{ - if (lastMasks.blocked == 0) - { - sigset_t newMask; - - sigemptyset(&newMask); - - // - // Block also the other signals that may be - // installed by the agent, that are those - // signals for which the function returns 2. - // - - for (int i = 0; i < 32; i++) - { - if (CheckSignal(i) > 0) - { - #ifdef DUMP - *logofs << "Loop: Disabling signal " << i << " '" - << DumpSignal(i) << "' in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - sigaddset(&newMask, i); - } - } - - sigprocmask(SIG_BLOCK, &newMask, &lastMasks.saved); - - lastMasks.blocked++; - } - #ifdef TEST - else - { - *logofs << "Loop: WARNING! Signals were already blocked in " - << "process with pid '" << getpid() << "'.\n" - << logofs_flush; - } - #endif -} - -void EnableSignals() -{ - if (lastMasks.blocked == 1) - { - #ifdef TEST - *logofs << "Loop: Enabling signals in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - sigprocmask(SIG_SETMASK, &lastMasks.saved, NULL); - - lastMasks.blocked = 0; - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Signals were not blocked in " - << "process with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Signals were not blocked in " - << "process with pid '" << getpid() << "'.\n"; - } -} - -void InstallSignal(int signal, int action) -{ - if (lastMasks.enabled[signal] == 1) - { - if (action == NX_SIGNAL_FORWARD) - { - #ifdef TEST - *logofs << "Loop: Forwarding handler for signal " << signal - << " '" << DumpSignal(signal) << "' in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - lastMasks.forward[signal] = 1; - - return; - } - #ifdef TEST - else - { - *logofs << "Loop: Reinstalling handler for signal " << signal - << " '" << DumpSignal(signal) << "' in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - } - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Installing handler for signal " << signal - << " '" << DumpSignal(signal) << "' in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - } - #endif - - if (signal == SIGALRM && isTimestamp(lastTimer.start)) - { - ResetTimer(); - } - - struct sigaction newAction; - - memset(&newAction, 0, sizeof(newAction)); - - newAction.sa_handler = HandleSignal; - - sigemptyset(&(newAction.sa_mask)); - - if (signal == SIGCHLD) - { - newAction.sa_flags = SA_NOCLDSTOP; - } - else - { - newAction.sa_flags = 0; - } - - sigaction(signal, &newAction, &lastMasks.action[signal]); - - lastMasks.enabled[signal] = 1; - - if (action == NX_SIGNAL_FORWARD) - { - lastMasks.forward[signal] = 1; - } -} - -void RestoreSignal(int signal) -{ - if (lastMasks.enabled[signal] == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Signal '" << DumpSignal(signal) - << " not installed in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Signal '" << DumpSignal(signal) - << " not installed in process with pid '" - << getpid() << "'.\n"; - - return; - } - - #ifdef TEST - *logofs << "Loop: Restoring handler for signal " << signal - << " '" << DumpSignal(signal) << "' in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if (signal == SIGALRM && isTimestamp(lastTimer.start)) - { - ResetTimer(); - } - - sigaction(signal, &lastMasks.action[signal], NULL); - - lastMasks.enabled[signal] = 0; - lastMasks.forward[signal] = 0; -} - -void HandleSignal(int signal) -{ - if (logofs == NULL) - { - logofs = &cerr; - } - - #if defined(UNSAFE) && (defined(TEST) || defined(INFO)) - - if (lastSignal != 0) - { - *logofs << "Loop: WARNING! Last signal is '" << lastSignal - << "', '" << DumpSignal(signal) << "' and not zero " - << "in process with pid '" << getpid() << "'.\n" - << logofs_flush; - } - - *logofs << "Loop: Signal '" << signal << "', '" - << DumpSignal(signal) << "' received in process " - << "with pid '" << getpid() << "'.\n" << logofs_flush; - - #endif - - if (getpid() != lastProxy && handler != NULL) - { - #if defined(UNSAFE) && (defined(TEST) || defined(INFO)) - *logofs << "Loop: Calling slave handler in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if ((*handler)(signal) == 0) - { - return; - } - } - - switch (signal) - { - case SIGUSR1: - { - if (proxy != NULL && lastSignal == 0) - { - lastSignal = SIGUSR1; - } - - break; - } - case SIGUSR2: - { - if (proxy != NULL && lastSignal == 0) - { - lastSignal = SIGUSR2; - } - - break; - } - case SIGPIPE: - { - // - // It can happen that SIGPIPE is delivered - // to the proxy even in the case some other - // descriptor is unexpectedly closed. - // - // if (agentFD[1] != -1) - // { - // cerr << "Info" << ": Received signal 'SIGPIPE'. " - // << "Closing agent conection.\n"; - // - // shutdown(agentFD[1], SHUT_RDWR); - // } - // - - break; - } - case SIGALRM: - { - // - // Nothing to do. Just wake up the - // process on blocking operations. - // - - break; - } - case SIGCHLD: - { - // - // Check if any of our children has exited. - // - - if (HandleChildren() != 0) - { - signal = 0; - } - - // - // Don't save this signal or it will override - // any previous signal sent by child before - // exiting. - // - - break; - } - - #ifdef __CYGWIN32__ - - case 12: - { - // - // Nothing to do. This signal is what is delivered - // by the Cygwin library when trying use a shared - // memory function if the daemon is not running. - // - - #ifdef TEST - *logofs << "Loop: WARNING! Received signal '12' in " - << "process with pid '" << getpid() << "'.\n" - << logofs_flush; - - *logofs << "Loop: WARNING! Please check that the " - << "cygserver daemon is running.\n" - << logofs_flush; - #endif - - break; - } - - #endif - - default: - { - // - // Register the signal so we can handle it - // inside the main loop. We will probably - // dispose any resource and exit. - // - - if (getpid() == lastProxy) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Registering end of session request " - << "due to signal '" << signal << "', '" - << DumpSignal(signal) << "'.\n" - << logofs_flush; - #endif - - lastSignal = signal; - } - else - { - // - // This is a child, so exit immediately. - // - - HandleCleanup(); - } - } - } - - if (signal != 0 && lastMasks.forward[signal] == 1) - { - if (lastMasks.action[signal].sa_handler != NULL && - lastMasks.action[signal].sa_handler != HandleSignal) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Forwarding signal '" << signal << "', '" - << DumpSignal(signal) << "' to previous handler.\n" - << logofs_flush; - #endif - - lastMasks.action[signal].sa_handler(signal); - } - #ifdef WARNING - else if (lastMasks.action[signal].sa_handler == NULL) - { - *logofs << "Loop: WARNING! Parent requested to forward " - << "signal '" << signal << "', '" << DumpSignal(signal) - << "' but didn't set a handler.\n" << logofs_flush; - } - #endif - } -} - -int HandleChildren() -{ - // - // Try to waitpid() for each child because the - // call might have return ECHILD and so we may - // have lost any of the processes. - // - - if (IsRunning(lastDialog) && HandleChild(lastDialog) == 1) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Resetting pid of last dialog process " - << "in handler.\n" << logofs_flush; - #endif - - SetNotRunning(lastDialog); - - if (proxy != NULL) - { - proxy -> handleResetAlert(); - } - - return 1; - } - - if (IsRunning(lastWatchdog) && HandleChild(lastWatchdog) == 1) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Watchdog is gone. Setting the last " - << "signal to SIGHUP.\n" << logofs_flush; - #endif - - lastSignal = SIGHUP; - - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Resetting pid of last watchdog process " - << "in handler.\n" << logofs_flush; - #endif - - SetNotRunning(lastWatchdog); - - return 1; - } - - // - // The house-keeping process exits after a - // number of iterations to keep the memory - // pollution low. It is restarted on demand - // by the lower layers, using the callback - // function. - // - - if (IsRunning(lastKeeper) && HandleChild(lastKeeper) == 1) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Resetting pid of last house-keeping " - << "process in handler.\n" << logofs_flush; - #endif - - SetNotRunning(lastKeeper); - - return 1; - } - - // - // The pid will be checked by the code - // that registered the child. - // - - if (IsRunning(lastChild)) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Resetting pid of last child process " - << "in handler.\n" << logofs_flush; - #endif - - SetNotRunning(lastChild); - - return 1; - } - - proxy->checkSlaves(); - - // - // This can actually happen either because we - // reset the pid of the child process as soon - // as we kill it, or because of a child process - // of our parent. - // - - #if defined(UNSAFE) && (defined(TEST) || defined(INFO)) - *logofs << "Loop: Ignoring signal received for the " - << "unregistered child.\n" << logofs_flush; - #endif - - return 0; -} - -int HandleChild(int child) -{ - int pid; - - int status = 0; - int options = WNOHANG | WUNTRACED; - - while ((pid = waitpid(child, &status, options)) && - pid == -1 && EGET() == EINTR); - - return CheckChild(pid, status); -} - -int WaitChild(int child, const char* label, int force) -{ - int pid; - - int status = 0; - int options = WUNTRACED; - - for (;;) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Waiting for the " << label - << " process '" << child << "' to die.\n" - << logofs_flush; - #endif - - pid = waitpid(child, &status, options); - - if (pid == -1 && EGET() == EINTR) - { - if (force == 0) - { - return 0; - } - - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring signal while " - << "waiting for the " << label << " process '" - << child << "' to die.\n" - << logofs_flush; - #endif - - continue; - } - - break; - } - - return (EGET() == ECHILD ? 1 : CheckChild(pid, status)); -} - -int CheckChild(int pid, int status) -{ - lastStatus = 0; - - if (pid > 0) - { - if (WIFSTOPPED(status)) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Child process '" << pid << "' was stopped " - << "with signal " << (WSTOPSIG(status)) << ".\n" - << logofs_flush; - #endif - - return 0; - } - else - { - if (WIFEXITED(status)) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Child process '" << pid << "' exited " - << "with status '" << (WEXITSTATUS(status)) - << "'.\n" << logofs_flush; - #endif - - lastStatus = WEXITSTATUS(status); - } - else if (WIFSIGNALED(status)) - { - if (CheckSignal(WTERMSIG(status)) != 1) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Child process '" << pid - << "' died because of signal " << (WTERMSIG(status)) - << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Child process '" << pid - << "' died because of signal " << (WTERMSIG(status)) - << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n"; - } - #if defined(UNSAFE) && defined(TEST) - else - { - *logofs << "Loop: Child process '" << pid - << "' died because of signal " << (WTERMSIG(status)) - << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n" - << logofs_flush; - } - #endif - - lastStatus = 1; - } - - return 1; - } - } - else if (pid < 0) - { - if (EGET() != ECHILD) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to waitpid failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to waitpid failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - HandleCleanup(); - } - - // - // This can happen when the waitpid() is - // blocking, as the SIGCHLD is received - // within the call. - // - - #ifdef TEST - *logofs << "Loop: No more children processes running.\n" - << logofs_flush; - #endif - - return 1; - } - - return 0; -} - -void RegisterChild(int child) -{ - #if defined(TEST) || defined(INFO) - - if (IsNotRunning(lastChild)) - { - *logofs << "Loop: Registering child process '" << child - << "' in process with pid '" << getpid() - << "'.\n" << logofs_flush; - } - else - { - *logofs << "Loop: WARNING! Overriding registered child '" - << lastChild << "' with new child '" << child - << "' in process with pid '" << getpid() - << "'.\n" << logofs_flush; - } - - #endif - - lastChild = child; -} - -int CheckParent(const char *name, const char *type, int parent) -{ - if (parent != getppid() || parent == 1) - { - #ifdef WARNING - *logofs << name << ": WARNING! Parent process appears " - << "to be dead. Exiting " << type << ".\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Parent process appears " - << "to be dead. Exiting " << type << ".\n"; - - return 0; - } - - return 1; -} - -void HandleTimer(int signal) -{ - if (signal == SIGALRM) - { - if (isTimestamp(lastTimer.start)) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Timer expired at " << strMsTimestamp() - << " in process with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if (proxy != NULL) - { - proxy -> handleTimer(); - } - - ResetTimer(); - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Inconsistent timer state " - << " in process with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Inconsistent timer state " - << " in process with pid '" << getpid() << "'.\n"; - } - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Inconsistent signal '" - << signal << "', '" << DumpSignal(signal) - << "' received in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Inconsistent signal '" - << signal << "', '" << DumpSignal(signal) - << "' received in process with pid '" - << getpid() << "'.\n"; - } -} - -void SetTimer(int value) -{ - getNewTimestamp(); - - if (isTimestamp(lastTimer.start)) - { - int diffTs = diffTimestamp(lastTimer.start, getTimestamp()); - - if (diffTs > lastTimer.next.tv_usec / 1000 * 2) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Timer missed to expire at " - << strMsTimestamp() << " in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Timer missed to expire at " - << strMsTimestamp() << " in process with pid '" - << getpid() << "'.\n"; - - HandleTimer(SIGALRM); - } - else - { - #ifdef TEST - *logofs << "Loop: Timer already running at " - << strMsTimestamp() << " in process with pid '" - << getpid() << "'.\n" << logofs_flush; - #endif - - return; - } - } - - // - // Save the former handler. - // - - struct sigaction action; - - memset(&action, 0, sizeof(action)); - - action.sa_handler = HandleTimer; - - sigemptyset(&action.sa_mask); - - action.sa_flags = 0; - - sigaction(SIGALRM, &action, &lastTimer.action); - - // - // Start the timer. - // - - lastTimer.next = getTimestamp(value); - - struct itimerval timer; - - timer.it_interval = lastTimer.next; - timer.it_value = lastTimer.next; - - #ifdef TEST - *logofs << "Loop: Timer set to " << lastTimer.next.tv_sec - << " S and " << lastTimer.next.tv_usec / 1000 - << " Ms at " << strMsTimestamp() << " in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - if (setitimer(ITIMER_REAL, &timer, &lastTimer.value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to setitimer failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to setitimer failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - lastTimer.next = nullTimestamp(); - - return; - } - - lastTimer.start = getTimestamp(); -} - -void ResetTimer() -{ - if (isTimestamp(lastTimer.start) == 0) - { - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Timer not running in process " - << "with pid '" << getpid() << "'.\n" - << logofs_flush; - #endif - - return; - } - - #if defined(UNSAFE) && defined(TEST) - *logofs << "Loop: Timer reset at " << strMsTimestamp() - << " in process with pid '" << getpid() - << "'.\n" << logofs_flush; - #endif - - // - // Restore the old signal mask and timer. - // - - if (setitimer(ITIMER_REAL, &lastTimer.value, NULL) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to setitimer failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to setitimer failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - - if (sigaction(SIGALRM, &lastTimer.action, NULL) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to sigaction failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to sigaction failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - } - - lastTimer.start = lastTimer.next = nullTimestamp(); -} - -// -// Open TCP or UNIX file socket to listen for remote proxy -// and block until remote connects. If successful close -// the listening socket and return FD on which the other -// party is connected. -// - -int WaitForRemote(ChannelEndPoint &socketAddress) -{ - char hostLabel[DEFAULT_STRING_LENGTH] = { 0 }; - char *socketUri = NULL; - - int retryAccept = -1; - - int proxyFD = -1; - int newFD = -1; - - int acceptIPAddr = 0; - - if (socketAddress.isTCPSocket()) - { - - // - // Get IP address of host to be awaited. - // - - if (*acceptHost != '\0') - { - acceptIPAddr = GetHostAddress(acceptHost); - - if (acceptIPAddr == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Cannot accept connections from unknown host '" - << acceptHost << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot accept connections from unknown host '" - << acceptHost << "'.\n"; - - goto WaitForRemoteError; - } - snprintf(hostLabel, sizeof(hostLabel), "'%s'", acceptHost); - } - else - { - strcpy(hostLabel, "any host"); - } - - long bindPort; - if (socketAddress.getTCPHostAndPort(NULL, &bindPort)) - { - socketAddress.setSpec(loopbackBind ? "localhost" : "*", bindPort); - } - else - { - // This should never happen - cerr << "Error" << ": Unable to change bind host\n"; - } - } - else if (socketAddress.isUnixSocket()) - strcpy(hostLabel, "this host"); - else - strcpy(hostLabel, "unknown origin (something went wrong!!!)"); - - - proxyFD = ListenConnection(socketAddress, "NX"); - - socketAddress.getSpec(&socketUri); - #ifdef TEST - *logofs << "Loop: Waiting for connection from " - << hostLabel << " on socket '" << socketUri - << "'.\n" << logofs_flush; - #endif - cerr << "Info" << ": Waiting for connection from " - << hostLabel << " on socket '" << socketUri - << "'.\n"; - free(socketUri); - - // - // How many times to loop waiting for connections - // from the selected host? Each loop wait for at - // most 20 seconds so a default value of 3 gives - // a timeout of 1 minute. - // - // TODO: Handling of timeouts and retry attempts - // must be rewritten. - // - - retryAccept = control -> OptionProxyRetryAccept; - - for (;;) - { - fd_set readSet; - - FD_ZERO(&readSet); - FD_SET(proxyFD, &readSet); - - T_timestamp selectTs; - - selectTs.tv_sec = 20; - selectTs.tv_usec = 0; - - int result = select(proxyFD + 1, &readSet, NULL, NULL, &selectTs); - - getNewTimestamp(); - - if (result == -1) - { - if (EGET() == EINTR) - { - if (CheckAbort() != 0) - { - goto WaitForRemoteError; - } - - continue; - } - - #ifdef PANIC - *logofs << "Loop: PANIC! Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Call to select failed. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - goto WaitForRemoteError; - } - else if (result > 0 && FD_ISSET(proxyFD, &readSet)) - { - - sockaddr_in newAddrINET; - - if (socketAddress.isUnixSocket()) - { - socklen_t addrLen = sizeof(sockaddr_un); - newFD = accept(proxyFD, NULL, &addrLen); - } - else if (socketAddress.isTCPSocket()) - { - socklen_t addrLen = sizeof(sockaddr_in); - newFD = accept(proxyFD, (sockaddr *) &newAddrINET, &addrLen); - } - if (newFD == -1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to accept failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Call to accept failed. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - goto WaitForRemoteError; - } - - if (socketAddress.isUnixSocket()) - { - - char * unixPath = NULL; - socketAddress.getUnixPath(&unixPath); - #ifdef TEST - *logofs << "Loop: Accepted connection from this host on Unix file socket '" - << unixPath << "'.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Accepted connection from this host on Unix file socket '" - << unixPath << "'.\n"; - free(unixPath); - - break; - } - else if (socketAddress.isTCPSocket()) - { - - char *connectedHost = inet_ntoa(newAddrINET.sin_addr); - - if (*acceptHost == '\0' || (int) newAddrINET.sin_addr.s_addr == acceptIPAddr) - { - - #ifdef TEST - - unsigned int connectedPort = ntohs(newAddrINET.sin_port); - - *logofs << "Loop: Accepted connection from '" << connectedHost - << "' with port '" << connectedPort << "'.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Accepted connection from '" - << connectedHost << "'.\n"; - - break; - } - else - { - #ifdef PANIC - *logofs << "Loop: WARNING! Refusing connection from '" << connectedHost - << "' on port '" << socketAddress.getTCPPort() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Refusing connection from '" - << connectedHost << "'.\n"; - } - - // - // Not the best way to elude a DOS attack... - // - - sleep(5); - - close(newFD); - - } - - } - - if (--retryAccept == 0) - { - if (socketAddress.isUnixSocket()) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Connection via Unix file socket from this host " - << "could not be established.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Connection via Unix file socket from this host " - << "could not be established.\n"; - } - else if (*acceptHost == '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! Connection with remote host " - << "could not be established.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Connection with remote host " - << "could not be established.\n"; - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Connection with remote host '" - << acceptHost << "' could not be established.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Connection with remote host '" - << acceptHost << "' could not be established.\n"; - } - - goto WaitForRemoteError; - } - else - { - handleCheckSessionInConnect(); - } - } - - close(proxyFD); - - return newFD; - -WaitForRemoteError: - - close(proxyFD); - - HandleCleanup(); -} - -int PrepareProxyConnectionTCP(char** hostName, long int* portNum, int* timeout, int* proxyFD, int* reason) -{ - - if (!proxyFD) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionTCP). " - << "'proxyFD' must not be a NULL pointer.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Implementation error (PrepareProxyConnectionTCP). " - << "'proxyFD' must not be a NULL pointer.\n"; - - return -1; - } - - if (!reason) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionTCP). " - << "'reason' must not be a NULL pointer.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Implementation error (PrepareProxyConnectionTCP). " - << "'reason' must not be a NULL pointer.\n"; - - return -1; - } - - int remoteIPAddr = GetHostAddress(*hostName); - if (remoteIPAddr == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unknown remote host '" - << *hostName << "'.\n" << logofs_flush; - #endif - cerr << "Error" << ": Unknown remote host '" - << *hostName << "'.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Connecting to remote host '" - << *hostName << ":" << *portNum << "'.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Connecting to remote host '" - << *hostName << ":" << *portNum << "'.\n" - << logofs_flush; - - *proxyFD = -1; - *reason = -1; - - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(*portNum); - addr.sin_addr.s_addr = remoteIPAddr; - - *proxyFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC); - *reason = EGET(); - - if (*proxyFD == -1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to socket failed. " - << "Error is " << *reason << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to socket failed. " - << "Error is " << *reason << " '" << ESTR() - << "'.\n"; - return -1; - - } - else if (SetReuseAddress(*proxyFD) < 0) - { - return -1; - } - - // - // Ensure operation is timed out - // if there is a network problem. - // - - if (timeout) - SetTimer(*timeout); - else - SetTimer(20000); - - int result = connect(*proxyFD, (sockaddr *) &addr, sizeof(sockaddr_in)); - - *reason = EGET(); - - ResetTimer(); - - return result; - -} - -int PrepareProxyConnectionUnix(char** path, int* timeout, int* proxyFD, int* reason) -{ - - if (!proxyFD) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionUnix). " - << "proxyFD must not be a NULL pointer.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Implementation error (PrepareProxyConnectionUnix). " - << "proxyFD must not be a NULL pointer.\n"; - - return -1; - } - - if (!reason) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionUnix). " - << "'reason' must not be a NULL pointer.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Implementation error (PrepareProxyConnectionUnix). " - << "'reason' must not be a NULL pointer.\n"; - - return -1; - } - - /* FIXME: Add socket file existence and permission checks */ - - *proxyFD = -1; - *reason = -1; - - sockaddr_un addr; - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, *path, 108 - 1); - - *proxyFD = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC); - *reason = EGET(); - - if (*proxyFD == -1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Call to socket failed. " - << "Error is " << *reason << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to socket failed. " - << "Error is " << *reason << " '" << ESTR() - << "'.\n"; - - return -1; - } - - // - // Ensure operation is timed out - // if there is a network problem. - // - - if (timeout) - SetTimer(*timeout); - else - SetTimer(20000); - - int result = connect(*proxyFD, (sockaddr *) &addr, sizeof(sockaddr_un)); - - *reason = EGET(); - - ResetTimer(); - - return result; -} - -// -// Connect to remote proxy. If successful -// return FD of connection, else return -1. -// - -int ConnectToRemote(ChannelEndPoint &socketAddress) -{ - - // - // How many times we retry to connect to remote - // host / Unix domain socket in case of failure? - // - - int retryConnect = control -> OptionProxyRetryConnect; - - // - // Show an alert after 20 seconds and use the - // same timeout to interrupt the connect. The - // retry timeout is incremental, starting from - // 100 miliseconds up to 1 second. - // - - int alertTimeout = 20000; - int connectTimeout = 20000; - int retryTimeout = 100; - - T_timestamp lastRetry = getNewTimestamp(); - - int result = -1; - int reason = -1; - int proxyFD = -1; - - char *hostName = NULL; - long int portNum = -1; - char *unixPath = NULL; - - for (;;) - { - - #ifdef DEBUG - *logofs << "Loop: Timer set to " << connectTimeout / 1000 - << " S " << "with retry set to " << retryConnect - << " in process with pid '" << getpid() - << "'.\n" << logofs_flush; - #endif - - if (socketAddress.getUnixPath(&unixPath)) - result = PrepareProxyConnectionUnix(&unixPath, &connectTimeout, &proxyFD, &reason); - else if (socketAddress.getTCPHostAndPort(&hostName, &portNum)) - result = PrepareProxyConnectionTCP(&hostName, &portNum, &connectTimeout, &proxyFD, &reason); - - if (result < 0) - { - close(proxyFD); - - if (CheckAbort() != 0) - { - goto ConnectToRemoteError; - } - else if (--retryConnect == 0) - { - ESET(reason); - - if (socketAddress.isUnixSocket()) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Connection to Unix file socket '" - << unixPath << "' failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Connection to Unix file socket '" - << unixPath << "' failed. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - } - else - { - - #ifdef PANIC - *logofs << "Loop: PANIC! Connection to '" << hostName - << ":" << portNum << "' failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Connection to '" << hostName - << ":" << portNum << "' failed. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - } - goto ConnectToRemoteError; - } - else - { - #ifdef TEST - *logofs << "Loop: Sleeping " << retryTimeout - << " ms before retrying.\n" - << logofs_flush; - #endif - - usleep(retryTimeout * 1000); - - retryTimeout <<= 1; - - if (retryTimeout > 1000 * 1000) - { - retryTimeout = 1000 * 1000; - } - } - - // - // Check if it is time to show an alert dialog. - // - - if (diffTimestamp(lastRetry, getNewTimestamp()) >= - (alertTimeout - control -> LatencyTimeout)) - { - if (IsNotRunning(lastDialog)) - { - handleCheckSessionInConnect(); - - // - // Wait for the dialog process to die - // unless a signal is received. - // - - while (IsRunning(lastDialog)) - { - WaitChild(lastDialog, "dialog", 0); - - if (CheckAbort() != 0) - { - // - // The client ignores the TERM signal - // on Windows. - // - - #ifdef __CYGWIN32__ - - KillProcess(lastDialog, "dialog", SIGKILL, 1); - - #else - - KillProcess(lastDialog, "dialog", SIGTERM, 1); - - #endif - - goto ConnectToRemoteError; - } - } - - lastRetry = getTimestamp(); - } - } - #ifdef TEST - { - *logofs << "Loop: Not showing the dialog with " - << (diffTimestamp(lastRetry, getTimestamp()) / 1000) - << " seconds elapsed.\n" << logofs_flush; - } - #endif - - ESET(reason); - - #ifdef TEST - if (unixPath && unixPath[0] != '\0' ) - { - *logofs << "Loop: Connection to Unix socket file '" - << unixPath << "' failed with error '" - << ESTR() << "'. Retrying.\n" - << logofs_flush; - } - else - { - *logofs << "Loop: Connection to '" << hostName - << ":" << portNum << "' failed with error '" - << ESTR() << "'. Retrying.\n" - << logofs_flush; - } - #endif - } - else - { - // - // Connection was successful. - // - - break; - } - } - - return proxyFD; - -ConnectToRemoteError: - - if (proxyFD != -1) - { - close(proxyFD); - } - - HandleCleanup(); -} - -// -// Make a string of options for the remote -// proxy and write it to the descriptor. -// The string includes the local version. -// - -int SendProxyOptions(int fd) -{ - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - // - // Send the "compatibility" version first, then our - // actual version. Old proxies will take the first - // value and ignore the second. - // - - sprintf(options, "NXPROXY-%s-%i.%i.%i", - control -> NXPROXY_COMPATIBILITY_VERSION, - control -> LocalVersionMajor, - control -> LocalVersionMinor, - control -> LocalVersionPatch); - - // - // If you want to send options from proxy - // initiating the connection use something - // like this: - // - // if (WE_PROVIDE_CREDENTIALS) - // { - // sprintf(options + strlen(options), "%s=%s", option, value); - // } - // - // If you want to send options according to - // local proxy mode use something like this: - // - // if (control -> ProxyMode == proxy_client) - // { - // sprintf(options + strlen(options), "%s=%s", option, value); - // } - // - - // - // Send the authorization cookie if any. We assume - // user can choose to not provide any auth cookie - // and allow any connection to be accepted. - // - - if (WE_PROVIDE_CREDENTIALS && *authCookie != '\0') - { - sprintf(options + strlen(options), " cookie=%s,", authCookie); - } - else - { - sprintf(options + strlen(options), " "); - } - - // - // Now link characteristics and compression - // options. Delta compression, as well as - // preferred pack method, are imposed by - // client proxy. - // - - if (control -> ProxyMode == proxy_client) - { - sprintf(options + strlen(options), "link=%s,pack=%s,cache=%s,", - linkSpeedName, packMethodName, cacheSizeName); - - if (*bitrateLimitName != '\0') - { - sprintf(options + strlen(options), "limit=%s,", - bitrateLimitName); - } - - // - // Let the user disable the render extension - // and let the X client proxy know if it can - // short-circuit the X replies. Also pass - // along the session type to ensure that the - // remote proxy gets the right value. - // - - sprintf(options + strlen(options), "render=%d,taint=%d,", - (control -> HideRender == 0), - control -> TaintReplies); - - if (*sessionType != '\0') - { - sprintf(options + strlen(options), "type=%s,", sessionType); - } - else - { - sprintf(options + strlen(options), "type=default,"); - } - - // - // Add the 'strict' option, if needed. - // - - // Since ProtoStep7 (#issue 108) - if (useStrict != -1) - { - sprintf(options + strlen(options), "strict=%d,", useStrict); - } - - // - // Tell the remote the size of the shared - // memory segment. - // - - // Since ProtoStep7 (#issue 108) - if (*shsegSizeName != '\0') - { - sprintf(options + strlen(options), "shseg=%s,", shsegSizeName); - } - - // - // Send image cache parameters. - // - - sprintf(options + strlen(options), "images=%s,", imagesSizeName); - - sprintf(options + strlen(options), "delta=%d,stream=%d,data=%d ", - control -> LocalDeltaCompression, - control -> LocalStreamCompressionLevel, - control -> LocalDataCompressionLevel); - } - else - { - // - // If no special compression level was selected, - // server side will use compression levels set - // by client. - // - - if (control -> LocalStreamCompressionLevel < 0) - { - sprintf(options + strlen(options), "stream=default,"); - } - else - { - sprintf(options + strlen(options), "stream=%d,", - control -> LocalStreamCompressionLevel); - } - - if (control -> LocalDataCompressionLevel < 0) - { - sprintf(options + strlen(options), "data=default "); - } - else - { - sprintf(options + strlen(options), "data=%d ", - control -> LocalDataCompressionLevel); - } - } - - #ifdef TEST - *logofs << "Loop: Sending remote options '" - << options << "'.\n" << logofs_flush; - #endif - - return WriteLocalData(fd, options, strlen(options)); -} - -int ReadProxyVersion(int fd) -{ - #ifdef TEST - *logofs << "Loop: Going to read the remote proxy version " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - // - // Read until the first space in string. - // We expect the remote version number. - // - - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - int result = ReadRemoteData(fd, options, sizeof(options), ' '); - - if (result <= 0) - { - if (result < 0) - { - if (control -> ProxyMode == proxy_server) - { - HandleAlert(ABORT_PROXY_NEGOTIATION_ALERT, 1); - } - - handleAlertInLoop(); - } - - return result; - } - - #ifdef TEST - *logofs << "Loop: Received remote version string '" - << options << "' from FD#" << fd << ".\n" - << logofs_flush; - #endif - - if (strncmp(options, "NXPROXY-", strlen("NXPROXY-")) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Parse error in remote options string '" - << options << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Parse error in remote options string '" - << options << "'.\n"; - - return -1; - } - - // - // Try to determine if this is a pre-2.0.0 - // version advertising itself as compatible - // with the 1.2.2. - // - - int major = -1; - int minor = -1; - int patch = -1; - - sscanf(options, "NXPROXY-%i.%i.%i-%i.%i.%i", &(control -> RemoteVersionMajor), - &(control -> RemoteVersionMinor), &(control -> RemoteVersionPatch), - &major, &minor, &patch); - - if (control -> RemoteVersionMajor == 1 && - control -> RemoteVersionMinor == 2 && - control -> RemoteVersionPatch == 2 && - major != -1 && minor != -1 && patch != -1) - { - #ifdef TEST - *logofs << "Loop: Read trailing remote version '" << major - << "." << minor << "." << patch << "'.\n" - << logofs_flush; - #endif - - control -> CompatVersionMajor = major; - control -> CompatVersionMinor = minor; - control -> CompatVersionPatch = patch; - - control -> RemoteVersionMajor = major; - control -> RemoteVersionMinor = minor; - control -> RemoteVersionPatch = patch; - } - else - { - // - // We read the remote version at the first - // round. If the second version is missing, - // we will retain the values read before. - // - - sscanf(options, "NXPROXY-%i.%i.%i-%i.%i.%i", &(control -> CompatVersionMajor), - &(control -> CompatVersionMinor), &(control -> CompatVersionPatch), - &(control -> RemoteVersionMajor), &(control -> RemoteVersionMinor), - &(control -> RemoteVersionPatch)); - } - - *logofs << "Loop: Identified remote version '" << control -> RemoteVersionMajor - << "." << control -> RemoteVersionMinor << "." << control -> RemoteVersionPatch - << "'.\n" << logofs_flush; - - *logofs << "Loop: Remote compatibility version '" << control -> CompatVersionMajor - << "." << control -> CompatVersionMinor << "." << control -> CompatVersionPatch - << "'.\n" << logofs_flush; - - *logofs << "Loop: Local version '" << control -> LocalVersionMajor - << "." << control -> LocalVersionMinor << "." << control -> LocalVersionPatch - << "'.\n" << logofs_flush; - - if (SetVersion() < 0) - { - if (control -> ProxyMode == proxy_server) - { - HandleAlert(WRONG_PROXY_VERSION_ALERT, 1); - } - - handleAlertInLoop(); - - return -1; - } - - return 1; -} - -int ReadProxyOptions(int fd) -{ - #ifdef TEST - *logofs << "Loop: Going to read the remote proxy options " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - int result = ReadRemoteData(fd, options, sizeof(options), ' '); - - if (result <= 0) - { - return result; - } - - #ifdef TEST - *logofs << "Loop: Received remote options string '" - << options << "' from FD#" << fd << ".\n" - << logofs_flush; - #endif - - // - // Get the remote options, delimited by a space character. - // Note that there will be a further initialization phase - // at the time proxies negotiate cache file to restore. - // - - if (ParseRemoteOptions(options) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Couldn't negotiate a valid " - << "session with remote NX proxy.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Couldn't negotiate a valid " - << "session with remote NX proxy.\n"; - - return -1; - } - - return 1; -} - -int SendProxyCaches(int fd) -{ - #ifdef TEST - *logofs << "Loop: Synchronizing local and remote caches.\n" - << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_client) - { - // - // Prepare a list of caches matching this - // session type and send it to the remote. - // - - #ifdef TEST - *logofs << "Loop: Going to send the list of local caches.\n" - << logofs_flush; - #endif - - SetCaches(); - - int entries = DEFAULT_REMOTE_CACHE_ENTRIES; - - const char prefix = 'C'; - - if (control -> LocalDeltaCompression == 0 || - control -> PersistentCacheEnableLoad == 0) - { - #ifdef TEST - *logofs << "Loop: Writing an empty list to FD#" << fd - << ".\n" << logofs_flush; - #endif - - return WriteLocalData(fd, "cachelist=none ", strlen("cachelist=none ")); - } - - int count = 0; - - #ifdef TEST - *logofs << "Loop: Looking for cache files in directory '" - << control -> PersistentCachePath << "'.\n" << logofs_flush; - #endif - - DIR *cacheDir = opendir(control -> PersistentCachePath); - - if (cacheDir != NULL) - { - dirent *dirEntry; - - int prologue = 0; - - while (((dirEntry = readdir(cacheDir)) != NULL) && (count < entries)) - { - if (*dirEntry -> d_name == prefix && - strlen(dirEntry -> d_name) == (MD5_LENGTH * 2 + 2)) - { - if (prologue == 0) - { - WriteLocalData(fd, "cachelist=", strlen("cachelist=")); - - prologue = 1; - } - else - { - WriteLocalData(fd, ",", strlen(",")); - } - - #ifdef TEST - *logofs << "Loop: Writing entry '" << control -> PersistentCachePath - << "/" << dirEntry -> d_name << "' to FD#" << fd - << ".\n" << logofs_flush; - #endif - - // - // Write cache file name to the socket, - // including leading 'C-' or 'S-'. - // - - WriteLocalData(fd, dirEntry -> d_name, MD5_LENGTH * 2 + 2); - - count++; - } - } - - closedir(cacheDir); - } - - if (count == 0) - { - #ifdef TEST - *logofs << "Loop: Writing an empty list to FD#" << fd - << ".\n" << logofs_flush; - #endif - - return WriteLocalData(fd, "cachelist=none ", strlen("cachelist=none ")); - } - else - { - return WriteLocalData(fd, " ", 1); - } - } - else - { - // - // Send back the selected cache name. - // - - #ifdef TEST - *logofs << "Loop: Going to send the selected cache.\n" - << logofs_flush; - #endif - - char buffer[DEFAULT_STRING_LENGTH]; - - if (control -> PersistentCacheName != NULL) - { - #ifdef TEST - *logofs << "Loop: Name of selected cache file is '" - << control -> PersistentCacheName << "'.\n" - << logofs_flush; - #endif - - sprintf(buffer, "cachefile=%s%s ", - *(control -> PersistentCacheName) == 'C' ? "S-" : "C-", - control -> PersistentCacheName + 2); - } - else - { - #ifdef TEST - *logofs << "Loop: No valid cache file was selected.\n" - << logofs_flush; - #endif - - sprintf(buffer, "cachefile=none "); - } - - #ifdef TEST - *logofs << "Loop: Sending string '" << buffer - << "' as selected cache file.\n" - << logofs_flush; - #endif - - return WriteLocalData(fd, buffer, strlen(buffer)); - } -} - -int ReadProxyCaches(int fd) -{ - if (control -> ProxyMode == proxy_client) - { - #ifdef TEST - *logofs << "Loop: Going to receive the selected proxy cache.\n" - << logofs_flush; - #endif - - // - // We will read the name of cache plus the stop character. - // - - char buffer[DEFAULT_STRING_LENGTH]; - - // - // Leave space for a trailing null. - // - - int result = ReadRemoteData(fd, buffer, sizeof("cachefile=") + MD5_LENGTH * 2 + 3, ' '); - - if (result <= 0) - { - return result; - } - - char *cacheName = strstr(buffer, "cachefile="); - - if (cacheName == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid cache file option '" - << buffer << "' provided by remote proxy.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid cache file option '" - << buffer << "' provided by remote proxy.\n"; - - HandleCleanup(); - } - - cacheName += strlen("cachefile="); - - if (control -> PersistentCacheName != NULL) - { - delete [] control -> PersistentCacheName; - } - - control -> PersistentCacheName = NULL; - - if (strncasecmp(cacheName, "none", strlen("none")) == 0) - { - #ifdef TEST - *logofs << "Loop: No cache file selected by remote proxy.\n" - << logofs_flush; - #endif - } - else if (strlen(cacheName) != MD5_LENGTH * 2 + 3 || - *(cacheName + MD5_LENGTH * 2 + 2) != ' ') - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid cache file name '" - << cacheName << "' provided by remote proxy.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid cache file name '" - << cacheName << "' provided by remote proxy.\n"; - - HandleCleanup(); - } - else - { - // - // It is "C-" + 32 + "\0". - // - - control -> PersistentCacheName = new char[MD5_LENGTH * 2 + 3]; - - *(cacheName + MD5_LENGTH * 2 + 2) = '\0'; - - strcpy(control -> PersistentCacheName, cacheName); - - #ifdef TEST - *logofs << "Loop: Cache file '" << control -> PersistentCacheName - << "' selected by remote proxy.\n" << logofs_flush; - #endif - } - } - else - { - #ifdef TEST - *logofs << "Loop: Going to receive the list of remote caches.\n" - << logofs_flush; - #endif - - SetCaches(); - - int size = ((MD5_LENGTH * 2 + 2) + strlen(",")) * DEFAULT_REMOTE_CACHE_ENTRIES + - strlen("cachelist=") + strlen(" ") + 1; - - char *buffer = new char[size]; - - int result = ReadRemoteData(fd, buffer, size - 1, ' '); - - if (result <= 0) - { - delete [] buffer; - - return result; - } - - #ifdef TEST - *logofs << "Loop: Read list of caches from remote side as '" - << buffer << "'.\n" << logofs_flush; - #endif - - // - // Prepare the buffer. What we want is a list - // like "cache1,cache2,cache2" terminated by - // null. - // - - *(buffer + strlen(buffer) - 1) = '\0'; - - if (strncasecmp(buffer, "cachelist=", strlen("cachelist=")) != 0) - { - #ifdef PANIC - *logofs << "Loop: Wrong format for list of cache files " - << "read from FD#" << fd << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Wrong format for list of cache files.\n"; - - delete [] buffer; - - return -1; - } - - control -> PersistentCacheName = GetLastCache(buffer, control -> PersistentCachePath); - - // - // Get rid of list of caches. - // - - delete [] buffer; - } - - return 1; -} - -int ReadForwarderVersion(int fd) -{ - #ifdef TEST - *logofs << "Loop: Going to negotiate the forwarder version.\n" - << logofs_flush; - #endif - - // - // Check if we actually expect the session cookie. - // - - if (*authCookie == '\0') - { - #ifdef TEST - *logofs << "Loop: No authentication cookie required " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - return 1; - } - - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - int result = ReadRemoteData(fd, options, sizeof(options), ' '); - - if (result <= 0) - { - return result; - } - - #ifdef TEST - *logofs << "Loop: Received forwarder version string '" << options - << "' from FD#" << fd << ".\n" << logofs_flush; - #endif - - if (strncmp(options, "NXSSH-", strlen("NXSSH-")) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Parse error in forwarder options string '" - << options << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Parse error in forwarder options string '" - << options << "'.\n"; - - return -1; - } - - // - // Accept whatever forwarder version. - // - - sscanf(options, "NXSSH-%i.%i.%i", &(control -> RemoteVersionMajor), - &(control -> RemoteVersionMinor), &(control -> RemoteVersionPatch)); - - #ifdef TEST - *logofs << "Loop: Read forwarder version '" << control -> RemoteVersionMajor - << "." << control -> RemoteVersionMinor << "." << control -> RemoteVersionPatch - << "'.\n" << logofs_flush; - #endif - - return 1; -} - -int ReadForwarderOptions(int fd) -{ - // - // Get the forwarder cookie. - // - - if (*authCookie == '\0') - { - #ifdef TEST - *logofs << "Loop: No authentication cookie required " - << "from FD#" << fd << ".\n" << logofs_flush; - #endif - - return 1; - } - - char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; - - int result = ReadRemoteData(fd, options, sizeof(options), ' '); - - if (result <= 0) - { - return result; - } - - #ifdef TEST - *logofs << "Loop: Received forwarder options string '" - << options << "' from FD#" << fd << ".\n" - << logofs_flush; - #endif - - if (ParseForwarderOptions(options) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Couldn't negotiate a valid " - << "cookie with the NX forwarder.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Couldn't negotiate a valid " - << "cookie with the NX forwarder.\n"; - - return -1; - } - - return 1; -} - -int ReadRemoteData(int fd, char *buffer, int size, char stop) -{ - #ifdef TEST - *logofs << "Loop: Going to read remote data from FD#" - << fd << ".\n" << logofs_flush; - #endif - - if (size >= MAXIMUM_REMOTE_OPTIONS_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Maximum remote options buffer " - << "limit exceeded.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Maximum remote options buffer " - << "limit exceeded.\n"; - - HandleCleanup(); - } - - while (remotePosition < (size - 1)) - { - int result = read(fd, remoteData + remotePosition, 1); - - getNewTimestamp(); - - if (result <= 0) - { - if (result == -1) - { - if (EGET() == EAGAIN) - { - #ifdef TEST - *logofs << "Loop: Reading data from FD#" << fd - << " would block.\n" << logofs_flush; - #endif - - return 0; - } - else if (EGET() == EINTR) - { - if (CheckAbort() != 0) - { - return -1; - } - - continue; - } - } - - #ifdef PANIC - *logofs << "Loop: PANIC! The remote NX proxy closed " - << "the connection.\n" << logofs_flush; - #endif - - cerr << "Error" << ": The remote NX proxy closed " - << "the connection.\n"; - - return -1; - } - else if (*(remoteData + remotePosition) == stop) - { - #ifdef TEST - *logofs << "Loop: Read stop character from FD#" - << fd << ".\n" << logofs_flush; - #endif - - remotePosition++; - - // - // Copy the fake terminating null - // in the buffer. - // - - *(remoteData + remotePosition) = '\0'; - - memcpy(buffer, remoteData, remotePosition + 1); - - #ifdef TEST - *logofs << "Loop: Remote string '" << remoteData - << "' read from FD#" << fd << ".\n" - << logofs_flush; - #endif - - int t = remotePosition; - - remotePosition = 0; - - return t; - } - else - { - // - // Make sure string received - // from far end is printable. - // - - if (isgraph(*(remoteData + remotePosition)) == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Non printable character decimal '" - << (unsigned int) *(remoteData + remotePosition) - << "' received in remote data from FD#" - << fd << ".\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Non printable character decimal '" - << (unsigned int) *(remoteData + remotePosition) - << "' received in remote data from FD#" - << fd << ".\n" << logofs_flush; - - *(remoteData + remotePosition) = ' '; - } - - #ifdef DEBUG - *logofs << "Loop: Read a further character " - << "from FD#" << fd << ".\n" - << logofs_flush; - #endif - - remotePosition++; - } - } - - *(remoteData + remotePosition) = '\0'; - - #ifdef PANIC - *logofs << "Loop: PANIC! Stop character missing " - << "from FD#" << fd << " after " << remotePosition - << " characters read in string '" << remoteData - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Stop character missing " - << "from FD#" << fd << " after " << remotePosition - << " characters read in string '" << remoteData - << "'.\n"; - - memcpy(buffer, remoteData, remotePosition); - - remotePosition = 0; - - return -1; -} - -static int -hexval(char c) { - if ((c >= '0') && (c <= '9')) - return c - '0'; - if ((c >= 'a') && (c <= 'f')) - return c - 'a' + 10; - if ((c >= 'A') && (c <= 'F')) - return c - 'A' + 10; - return -1; -} - -static void -URLDecodeInPlace(char *str) { - if (str) { - char *to = str; - while (str[0]) { - if ((str[0] == '%') && - (hexval(str[1]) >= 0) && - (hexval(str[2]) >= 0)) { - *(to++) = hexval(str[1]) * 16 + hexval(str[2]); - str += 3; - } - else - *(to++) = *(str++); - } - *to = '\0'; - } -} - -int WriteLocalData(int fd, const char *buffer, int size) -{ - int position = 0; - int ret = 0; - fd_set writeSet; - struct timeval selectTs = {30, 0}; - - while (position < size) - { - - // A write to a non-blocking socket may fail with EAGAIN. The problem is - // that cache data is done in several writes, and there's no easy way - // to handle failure without rewriting a significant amount of code. - // - // Bailing out of the outer loop would result in restarting the sending - // of the entire cache list, which would confuse the other side. - - FD_ZERO(&writeSet); - FD_SET(fd, &writeSet); - - ret = select(fd+1, NULL, &writeSet, NULL, &selectTs); - - #ifdef DEBUG - *logofs << "Loop: WriteLocalData: select() returned with a code of " << ret << " and remaining timeout of " - << selectTs.tv_sec << " sec, " << selectTs.tv_usec << "usec\n" << logofs_flush; - #endif - - if ( ret < 0 ) - { - *logofs << "Loop: Error in select() when writing data to FD#" << fd << ": " << strerror(EGET()) << "\n" << logofs_flush; - - if ( EGET() == EINTR ) - continue; - - return -1; - } - else if ( ret == 0 ) - { - *logofs << "Loop: Timeout expired in select() when writing data to FD#" << fd << ": " << strerror(EGET()) << "\n" << logofs_flush; - return -1; - } - - int result = write(fd, buffer + position, size - position); - - getNewTimestamp(); - - if (result <= 0) - { - if (result < 0 && (EGET() == EINTR || EGET() == EAGAIN || EGET() == EWOULDBLOCK)) - { - continue; - } - - #ifdef TEST - *logofs << "Loop: Error writing data to FD#" - << fd << ".\n" << logofs_flush; - #endif - - return -1; - } - - position += result; - } - - return position; -} - -// -// Parse the string passed by calling process in -// the environment. This is not necessarily the -// content of DISPLAY variable, but can be the -// parameters passed when creating the process -// or thread. -// - -int ParseEnvironmentOptions(const char *env, int force) -{ - // - // Be sure log file is valid. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - // - // Be sure we have a parameters repository - // and a context to jump into because this - // can be called before creating the proxy. - // - - if (control == NULL) - { - control = new Control(); - } - - if (setjmp(context) == 1) - { - #ifdef TEST - *logofs << "Loop: Out of the long jump while parsing " - << "the environment options.\n" - << logofs_flush; - #endif - - return -1; - } - - if (force == 0 && parsedOptions == 1) - { - #ifdef TEST - *logofs << "Loop: Skipping a further parse of environment " - << "options string '" << (env != NULL ? env : "") - << "'.\n" << logofs_flush; - #endif - - return 1; - } - - if (env == NULL || *env == '\0') - { - #ifdef TEST - *logofs << "Loop: Nothing to do with empty environment " - << "options string '" << (env != NULL ? env : "") - << "'.\n" << logofs_flush; - #endif - - return 0; - } - - #ifdef TEST - *logofs << "Loop: Going to parse the environment options " - << "string '" << env << "'.\n" - << logofs_flush; - #endif - - parsedOptions = 1; - - // - // Copy the string passed as parameter - // because we need to modify it. - // - - char opts[DEFAULT_DISPLAY_OPTIONS_LENGTH]; - - #ifdef VALGRIND - - memset(opts, '\0', DEFAULT_DISPLAY_OPTIONS_LENGTH); - - #endif - - if (strlen(env) >= DEFAULT_DISPLAY_OPTIONS_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Environment options string '" << env - << "' exceeds length of " << DEFAULT_DISPLAY_OPTIONS_LENGTH - << " characters.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Environment options string '" << env - << "' exceeds length of " << DEFAULT_DISPLAY_OPTIONS_LENGTH - << " characters.\n"; - - return -1; - } - - strcpy(opts, env); - - char *nextOpts = opts; - - // - // Ensure that DISPLAY environment variable - // (roughly) follows the X convention for - // transport notation. - // - - if (strncasecmp(opts, "nx/nx,:", 7) == 0 || - strncasecmp(opts, "nx,:", 4) == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Parse error in options string '" - << opts << "' at 'nx,:'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Parse error in options string '" - << opts << "' at 'nx,:'.\n"; - - return -1; - } - else if (strncasecmp(opts, "nx/nx,", 6) == 0) - { - nextOpts += 6; - } - else if (strncasecmp(opts, "nx,", 3) == 0) - { - nextOpts += 3; - } - else if (strncasecmp(opts, "nx:", 3) == 0) - { - nextOpts += 3; - } - else if (force == 0) - { - #ifdef TEST - *logofs << "Loop: Ignoring host X server display string '" - << opts << "'.\n" << logofs_flush; - #endif - - return 0; - } - - // - // Save here the name of the options file and - // parse it after all the other options. - // - - char fileOptions[DEFAULT_STRING_LENGTH] = { 0 }; - - // - // The options string is intended to be a series - // of name/value tuples in the form name=value - // separated by the ',' character ended by a ':' - // followed by remote NX proxy port. - // - - char *name; - char *value; - - value = strrchr(nextOpts, ':'); - - if (value != NULL) - { - char *check = value + 1; - - if (*check == '\0' || isdigit(*check) == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify NX port in string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify NX port in string '" - << value << "'.\n"; - - return -1; - } - - proxyPort = atoi(check); - - // - // Get rid of the port specification. - // - - *value = '\0'; - } - else if (proxyPort == DEFAULT_NX_PROXY_PORT && force == 0) - { - // - // Complain only if user didn't specify - // the port on the command line. - // - - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify NX port in string '" - << opts << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify NX port in string '" - << opts << "'.\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Loop: Parsing options string '" - << nextOpts << "'.\n" << logofs_flush; - #endif - - // - // Now all the other optional parameters. - // - - name = strtok(nextOpts, "="); - - char connectHost[DEFAULT_STRING_LENGTH] = { 0 }; - long connectPort = -1; - - while (name) - { - value = strtok(NULL, ","); - URLDecodeInPlace(value); - - if (CheckArg("environment", name, value) < 0) - { - return -1; - } - - if (strcasecmp(name, "options") == 0) - { - strncpy(fileOptions, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "display") == 0) - { - strncpy(displayHost, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "link") == 0) - { - - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseLinkOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify 'link' option in string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify 'link' option in string '" - << value << "'.\n"; - if (ParseLinkOption("adsl") < 0) - return -1; - } - } - else if (strcasecmp(name, "limit") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseBitrateOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify option 'limit' in string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify option 'limit' in string '" - << value << "'.\n"; - - return -1; - } - } - else if (strcasecmp(name, "type") == 0) - { - // - // Type of session, for example "desktop", - // "application", "windows", etc. - // - - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - if (strcasecmp(value, "default") == 0) - { - *sessionType = '\0'; - } - else - { - strncpy(sessionType, value, DEFAULT_STRING_LENGTH - 1); - } - } - } - else if (strcasecmp(name, "listen") == 0) - { - char *socketUri = NULL; - if (connectSocket.getSpec(&socketUri)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't handle 'listen' and 'connect' parameters " - << "at the same time.\n" << logofs_flush; - - *logofs << "Loop: PANIC! Refusing 'listen' parameter with 'connect' being '" - << socketUri << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't handle 'listen' and 'connect' parameters " - << "at the same time.\n"; - - cerr << "Error" << ": Refusing 'listen' parameter with 'connect' being '" - << socketUri << "'.\n"; - - free(socketUri); - return -1; - } - - SetAndValidateChannelEndPointArg("local", name, value, listenSocket); - - } - else if (strcasecmp(name, "loopback") == 0) - { - loopbackBind = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "accept") == 0) - { - char *socketUri = NULL; - if (connectSocket.getSpec(&socketUri)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't handle 'accept' and 'connect' parameters " - << "at the same time.\n" << logofs_flush; - - *logofs << "Loop: PANIC! Refusing 'accept' parameter with 'connect' being '" - << socketUri << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't handle 'accept' and 'connect' parameters " - << "at the same time.\n"; - - cerr << "Error" << ": Refusing 'accept' parameter with 'connect' being '" - << socketUri << "'.\n"; - - free(socketUri); - return -1; - } - - strncpy(acceptHost, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "connect") == 0) - { - if (*acceptHost != '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't handle 'connect' and 'accept' parameters " - << "at the same time.\n" << logofs_flush; - - *logofs << "Loop: PANIC! Refusing 'connect' parameter with 'accept' being '" - << acceptHost << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't handle 'connect' and 'accept' parameters " - << "at the same time.\n"; - - cerr << "Error" << ": Refusing 'connect' parameter with 'accept' being '" - << acceptHost << "'.\n"; - - return -1; - } - if ((strncmp(value, "tcp:", 4) == 0) || (strncmp(value, "unix:", 5) == 0)) - SetAndValidateChannelEndPointArg("local", name, value, connectSocket); - else - // if the "connect" parameter does not start with "unix:" or "tcp:" assume - // old parameter usage style (providing hostname string only). - strcpy(connectHost, value); - } - else if (strcasecmp(name, "port") == 0) - { - connectPort = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "retry") == 0) - { - control -> OptionProxyRetryConnect = ValidateArg("local", name, value); - control -> OptionServerRetryConnect = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "session") == 0) - { - strncpy(sessionFileName, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "errors") == 0) - { - // - // The old name of the parameter was 'log' - // but the default name for the file is - // 'errors' so it is more logical to use - // the same name. - // - - strncpy(errorsFileName, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "root") == 0) - { - strncpy(rootDir, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "id") == 0) - { - strncpy(sessionId, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "stats") == 0) - { - control -> EnableStatistics = 1; - - strncpy(statsFileName, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "cookie") == 0) - { - LowercaseArg("local", name, value); - - strncpy(authCookie, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "nodelay") == 0) - { - useNoDelay = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "policy") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - usePolicy = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "render") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - useRender = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "taint") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - useTaint = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "delta") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - control -> LocalDeltaCompression = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "data") == 0) - { - control -> LocalDataCompressionLevel = ValidateArg("local", name, value); - - if (control -> LocalDataCompressionLevel == 0) - { - control -> LocalDataCompression = 0; - } - else - { - control -> LocalDataCompression = 1; - } - } - else if (strcasecmp(name, "stream") == 0) - { - control -> LocalStreamCompressionLevel = ValidateArg("local", name, value); - - if (control -> LocalStreamCompressionLevel == 0) - { - control -> LocalStreamCompression = 0; - } - else - { - control -> LocalStreamCompression = 1; - } - } - else if (strcasecmp(name, "memory") == 0) - { - control -> LocalMemoryLevel = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "cache") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseCacheOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify cache size for string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify cache size for string '" - << value << "'.\n"; - - return -1; - } - } - else if (strcasecmp(name, "images") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseImagesOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify images cache size for string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify images cache size for string '" - << value << "'.\n"; - - return -1; - } - } - else if (strcasecmp(name, "shseg") == 0) - { - // - // The 'shmem' option is used by the agent, together - // with 'shpix' literal. We make the 'shseg' option - // specific to the proxy and use it to determine the - // size of the shared memory segment, or otherwise 0, - // if the use of the shared memory extension should - // not be enabled on the real X server. - // - - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParseShmemOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify size of shared memory " - << "segment in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify size of shared memory " - << "segment in string '" << value << "'.\n"; - - return -1; - } - } - else if (strcasecmp(name, "load") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - control -> PersistentCacheEnableLoad = ValidateArg("local", name, value); - - if (control -> PersistentCacheEnableLoad > 0) - { - control -> PersistentCacheEnableLoad = 1; - } - else - { - if (control -> PersistentCacheName != NULL) - { - delete [] control -> PersistentCacheName; - } - - control -> PersistentCacheName = NULL; - - control -> PersistentCacheEnableLoad = 0; - } - } - } - else if (strcasecmp(name, "save") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - control -> PersistentCacheEnableSave = ValidateArg("local", name, value); - - if (control -> PersistentCacheEnableSave > 0) - { - control -> PersistentCacheEnableSave = 1; - } - else - { - if (control -> PersistentCacheName != NULL) - { - delete [] control -> PersistentCacheName; - } - - control -> PersistentCacheName = NULL; - - control -> PersistentCacheEnableSave = 0; - } - } - } - else if (strcasecmp(name, "cups") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, cupsPort); - } - else if (strcasecmp(name, "sync") == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! No 'sync' channel in current version. " - << "Assuming 'cups' channel.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": No 'sync' channel in current version. " - << "Assuming 'cups' channel.\n"; - - SetAndValidateChannelEndPointArg("local", name, value, cupsPort); - } - else if (strcasecmp(name, "keybd") == 0 || - strcasecmp(name, "aux") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, auxPort); - } - else if (strcasecmp(name, "samba") == 0 || - strcasecmp(name, "smb") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, smbPort); - } - else if (strcasecmp(name, "media") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, mediaPort); - } - else if (strcasecmp(name, "http") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, httpPort); - } - else if (strcasecmp(name, "font") == 0) - { - strncpy(fontPort, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "slave") == 0) - { - SetAndValidateChannelEndPointArg("local", name, value, slavePort); - } - else if (strcasecmp(name, "mask") == 0) - { - control -> ChannelMask = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "timeout") == 0) - { - int timeout = ValidateArg("local", name, value); - - if (timeout == 0) - { - #ifdef TEST - *logofs << "Loop: Disabling timeout on broken " - << "proxy connection.\n" << logofs_flush; - #endif - - control -> ProxyTimeout = 0; - } - else - { - control -> ProxyTimeout = timeout * 1000; - } - } - else if (strcasecmp(name, "cleanup") == 0) - { - int cleanup = ValidateArg("local", name, value); - - if (cleanup == 0) - { - #ifdef TEST - *logofs << "Loop: Disabling grace timeout on " - << "proxy shutdown.\n" << logofs_flush; - #endif - - control -> CleanupTimeout = 0; - } - else - { - control -> CleanupTimeout = cleanup * 1000; - } - } - else if (strcasecmp(name, "pack") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else if (ParsePackOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify pack method for string '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify pack method for string '" - << value << "'.\n"; - if (ParsePackOption("nopack")<0) - return -1; - } - } - else if (strcasecmp(name, "core") == 0) - { - control -> EnableCoreDumpOnAbort = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "kill") == 0) - { - if (control -> KillDaemonOnShutdownNumber < - control -> KillDaemonOnShutdownLimit) - { - #ifdef TEST - *logofs << "Loop: WARNING! Adding process with pid '" - << ValidateArg("local", name, value) << " to the " - << "daemons to kill at shutdown.\n" - << logofs_flush; - #endif - - control -> KillDaemonOnShutdown[control -> - KillDaemonOnShutdownNumber] = - ValidateArg("local", name, value); - - control -> KillDaemonOnShutdownNumber++; - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Number of daemons to kill " - << "at shutdown exceeded.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Number of daemons to kill " - << "at shutdown exceeded.\n"; - } - } - else if (strcasecmp(name, "strict") == 0) - { - if (control -> ProxyMode == proxy_server) - { - PrintOptionIgnored("local", name, value); - } - else - { - useStrict = ValidateArg("local", name, value); - } - } - else if (strcasecmp(name, "encryption") == 0) - { - useEncryption = ValidateArg("local", name, value); - } - else if (strcasecmp(name, "product") == 0) - { - strncpy(productName, value, DEFAULT_STRING_LENGTH - 1); - } - else if (strcasecmp(name, "rootless") == 0 || - strcasecmp(name, "geometry") == 0 || - strcasecmp(name, "resize") == 0 || - strcasecmp(name, "fullscreen") == 0 || - strcasecmp(name, "keyboard") == 0 || - strcasecmp(name, "clipboard") == 0 || - strcasecmp(name, "streaming") == 0 || - strcasecmp(name, "backingstore") == 0 || - strcasecmp(name, "sleep") == 0 || - strcasecmp(name, "tolerancechecks") == 0) - { - #ifdef DEBUG - *logofs << "Loop: Ignoring agent option '" << name - << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - } - else if (strcasecmp(name, "composite") == 0 || - strcasecmp(name, "shmem") == 0 || - strcasecmp(name, "shpix") == 0 || - strcasecmp(name, "kbtype") == 0 || - strcasecmp(name, "client") == 0 || - strcasecmp(name, "shadow") == 0 || - strcasecmp(name, "shadowuid") == 0 || - strcasecmp(name, "shadowmode") == 0 || - strcasecmp(name, "clients") == 0 || - strcasecmp(name, "xinerama") == 0) - { - #ifdef DEBUG - *logofs << "Loop: Ignoring agent option '" << name - << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - } - else if (strcasecmp(name, "defer") == 0 || - strcasecmp(name, "tile") == 0 || - strcasecmp(name, "menu") == 0 || - strcasecmp(name, "state") == 0 ) - { - #ifdef DEBUG - *logofs << "Loop: Ignoring agent option '" << name - << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring unknown option '" - << name << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring unknown option '" - << name << "' with value '" << value << "'.\n"; - } - - name = strtok(NULL, "="); - - } // End of while (name) ... - - // Assemble the connectSocket channel end point if parameter values have been old-school... - if (connectSocket.disabled() && (connectHost[0] != '\0') && (proxyPort > 0 || connectPort > 0)) - { - if (connectPort < 0) - connectPort = proxyPort + DEFAULT_NX_PROXY_PORT_OFFSET; - - char tcpHostAndPort[DEFAULT_STRING_LENGTH] = { 0 }; - sprintf(tcpHostAndPort, "tcp:%s:%ld", connectHost, connectPort); - SetAndValidateChannelEndPointArg("local", name, tcpHostAndPort, connectSocket); - } - - #ifdef TEST - *logofs << "Loop: Completed parsing of string '" - << env << "'.\n" << logofs_flush; - #endif - - if ((*fileOptions != '\0') && (strncmp(fileOptions, "/dev/", 5) != 0) && (strncmp(fileOptions, "/proc/", 6) != 0) && (strncmp(fileOptions, "/sys/", 5) != 0)) - { - if (strcmp(fileOptions, optionsFileName) != 0) - { - #ifdef TEST - *logofs << "Loop: Reading options from '" << fileOptions - << "'.\n" << logofs_flush; - #endif - - if (ParseFileOptions(fileOptions) < 0) - { - return -1; - } - } - #ifdef WARNING - else - { - *logofs << "Loop: WARNING! Name of the options file " - << "specified multiple times. Not parsing " - << "again.\n" << logofs_flush; - } - #endif - - if (*optionsFileName == '\0') - { - strncpy(optionsFileName, value, DEFAULT_STRING_LENGTH - 1); - - #ifdef TEST - *logofs << "Loop: Assuming name of options file '" - << optionsFileName << "'.\n" - << logofs_flush; - #endif - } - } - - // - // If port where proxy is acting as an X server - // was not specified assume the same port where - // proxy is listening for the remote peer. - // - - if (xPort == DEFAULT_NX_X_PORT) - { - xPort = proxyPort; - } - - return 1; -} - -// -// Parse the command line options passed by user when -// running proxy in stand alone mode. Note that passing -// parameters this way is strongly discouraged. These -// command line switch can change (and they do often). -// Please, use the form "option=value" instead and set -// the DISPLAY environment variable. -// - -int ParseCommandLineOptions(int argc, const char **argv) -{ - // - // Be sure log file is valid. - // - - if (logofs == NULL) - { - logofs = &cerr; - } - - if (setjmp(context) == 1) - { - #ifdef TEST - *logofs << "Loop: Out of the long jump while parsing " - << "the command line options.\n" - << logofs_flush; - #endif - - return -1; - } - - // - // Be sure we have a parameters repository - // - - if (control == NULL) - { - control = new Control(); - } - - if (parsedCommand == 1) - { - #ifdef TEST - *logofs << "Loop: Skipping a further parse of command line options.\n" - << logofs_flush; - #endif - - return 1; - } - - #ifdef TEST - *logofs << "Loop: Going to parse the command line options.\n" - << logofs_flush; - #endif - - parsedCommand = 1; - - // - // Print out arguments. - // - - #ifdef TEST - - *logofs << "Loop: Argc is " << argc << ".\n" << logofs_flush; - - for (int argi = 0; argi < argc; argi++) - { - *logofs << "Loop: Argv[" << argi << "] is " << argv[argi] - << ".\n" << logofs_flush; - } - - #endif - - // - // Shall use getopt here. - // - - for (int argi = 1; argi < argc; argi++) - { - const char *nextArg = argv[argi]; - - if (*nextArg == '-') - { - switch (*(nextArg + 1)) - { - case 'h': - { - PrintUsageInfo(nextArg, 0); - - return -1; - } - case 'C': - { - // - // Start proxy in CLIENT mode. - // - - if (WE_SET_PROXY_MODE == 0) - { - #ifdef TEST - *logofs << "Loop: Setting local proxy mode to proxy_client.\n" - << logofs_flush; - #endif - - control -> ProxyMode = proxy_client; - } - else if (control -> ProxyMode != proxy_client) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't redefine local proxy to " - << "client mode.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't redefine local proxy to " - << "client mode.\n"; - - return -1; - } - - break; - } - case 'S': - { - // - // Start proxy in SERVER mode. - // - - if (WE_SET_PROXY_MODE == 0) - { - #ifdef TEST - *logofs << "Loop: Setting local proxy mode to proxy_server.\n" - << logofs_flush; - #endif - - control -> ProxyMode = proxy_server; - } - else if (control -> ProxyMode != proxy_server) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't redefine local proxy to " - << "server mode.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't redefine local proxy to " - << "server mode.\n"; - - return -1; - } - - break; - } - case 'v': - { - PrintVersionInfo(); - - return -1; - } - default: - { - PrintUsageInfo(nextArg, 1); - - // - // Function GetArg() is not used anymore. - // Add a dummy call to avoid the warning. - // - - if (0) - { - GetArg(argi, argc, argv); - } - - return -1; - } - } - } - else - { - if (nextArg) - { - // - // Try to parse the option as a remote host:port - // specification as in 'localhost:8'. Such a - // parameter can be specified at the end of the - // command line at the connecting side. - // - - char cHost[DEFAULT_STRING_LENGTH] = { '\0' }; - long cPort = 0; - - if (ParseHostOption(nextArg, cHost, cPort) > 0) - { - // - // Assume port is at a proxied display offset. - // - - proxyPort = cPort; - - cPort += DEFAULT_NX_PROXY_PORT_OFFSET; - connectSocket.setSpec(cHost, cPort); - - } - else if (ParseEnvironmentOptions(nextArg, 1) < 0) - { - return -1; - } - } - } - } - - return 1; -} - -// -// Set the variable to the values of host and -// port where this proxy is going to hook to -// an existing proxy. -// - -int ParseBindOptions(char **host, int *port) -{ - if (*bindHost != '\0') - { - *host = bindHost; - *port = bindPort; - - return 1; - } - else - { - return 0; - } -} - -// -// Read options from file and merge with environment. -// - -int ParseFileOptions(const char *file) -{ - char *fileName; - - if (*file != '/' && *file != '.') - { - char *filePath = GetSessionPath(); - - if (filePath == NULL) - { - cerr << "Error" << ": Cannot determine directory for NX option file.\n"; - - HandleCleanup(); - } - - fileName = new char[strlen(filePath) + strlen("/") + - strlen(file) + 1]; - - strcpy(fileName, filePath); - - strcat(fileName, "/"); - strcat(fileName, file); - - delete [] filePath; - } - else - { - fileName = new char[strlen(file) + 1]; - - strcpy(fileName, file); - } - - #ifdef TEST - *logofs << "Loop: Going to read options from file '" - << fileName << "'.\n" << logofs_flush; - #endif - - FILE *filePtr = fopen(fileName, "r"); - - if (filePtr == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't open options file '" << fileName - << "'. Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't open options file '" << fileName - << "'. Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] fileName; - - return -1; - } - - char options[DEFAULT_DISPLAY_OPTIONS_LENGTH]; - - #ifdef VALGRIND - - memset(options, '\0', DEFAULT_DISPLAY_OPTIONS_LENGTH); - - #endif - - if (fgets(options, DEFAULT_DISPLAY_OPTIONS_LENGTH, filePtr) == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't read options from file '" << fileName - << "'. Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't read options from file '" << fileName - << "'. Error is " << EGET() << " '" << ESTR() << "'.\n"; - - fclose(filePtr); - - delete [] fileName; - - return -1; - } - - fclose(filePtr); - - // - // Purge the newline and the other non- - // printable characters in the string. - // - - char *next = options; - - while (*next != '\0') - { - if (isprint(*next) == 0) - { - *next = '\0'; - } - - next++; - } - - #ifdef TEST - *logofs << "Loop: Read options '" << options << "' from file '" - << fileName << "'.\n" << logofs_flush; - #endif - - if (ParseEnvironmentOptions(options, 1) < 0) - { - delete [] fileName; - - return -1; - } - - delete [] fileName; - - return 1; -} - -// -// Parse the option string passed from the -// remote proxy at startup. -// - -int ParseRemoteOptions(char *opts) -{ - #ifdef TEST - *logofs << "Loop: Going to parse the remote options " - << "string '" << opts << "'.\n" - << logofs_flush; - #endif - - char *name; - char *value; - - // - // The options string is intended to be a series - // of name/value tuples in the form name=value - // separated by the ',' character. - // - - int hasCookie = 0; - int hasLink = 0; - int hasPack = 0; - int hasCache = 0; - int hasImages = 0; - int hasDelta = 0; - int hasStream = 0; - int hasData = 0; - int hasType = 0; - - // - // Get rid of the terminating space. - // - - if (*(opts + strlen(opts) - 1) == ' ') - { - *(opts + strlen(opts) - 1) = '\0'; - } - - name = strtok(opts, "="); - - while (name) - { - value = strtok(NULL, ","); - - if (CheckArg("remote", name, value) < 0) - { - return -1; - } - - if (strcasecmp(name, "cookie") == 0) - { - if (WE_PROVIDE_CREDENTIALS) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring remote option 'cookie' " - << "with value '" << value << "' when initiating " - << "connection.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring remote option 'cookie' " - << "with value '" << value << "' when initiating " - << "connection.\n"; - } - else if (strncasecmp(authCookie, value, strlen(authCookie)) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Authentication cookie '" << value - << "' doesn't match '" << authCookie << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Authentication cookie '" << value - << "' doesn't match '" << authCookie << "'.\n"; - - return -1; - } - - hasCookie = 1; - } - else if (strcasecmp(name, "link") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - if (*linkSpeedName != '\0' && strcasecmp(linkSpeedName, value) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding option 'link' " - << "with new value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Overriding option 'link' " - << "with new value '" << value << "'.\n"; - } - - if (ParseLinkOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify remote 'link' " - << "option in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify remote 'link' " - << "option in string '" << value << "'.\n"; - - return -1; - } - } - - hasLink = 1; - } - else if (strcasecmp(name, "pack") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - if (*packMethodName != '\0' && strcasecmp(packMethodName, value) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding option 'pack' " - << "with remote value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Overriding option 'pack' " - << "with remote value '" << value << "'.\n"; - } - - if (ParsePackOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid pack option '" - << value << "' requested by remote.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid pack option '" - << value << "' requested by remote.\n"; - - return -1; - } - } - - hasPack = 1; - } - else if (strcasecmp(name, "cache") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - // - // Cache size is sent as a hint of how much memory - // the remote proxy is going to consume. A very low - // powered thin client could choose to refuse the - // connection. - // - - if (ParseCacheOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify remote 'cache' " - << "option in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify remote 'cache' " - << "option in string '" << value << "'.\n"; - - return -1; - } - } - - hasCache = 1; - } - else if (strcasecmp(name, "images") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - // - // Images cache size is sent as a hint. - // There is no obbligation for the local - // proxy to use the persistent cache. - // - - if (ParseImagesOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify remote 'images' " - << "option in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify remote 'images' " - << "option in string '" << value << "'.\n"; - - return -1; - } - } - - hasImages = 1; - } - else if (strcasecmp(name, "limit") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - if (*bitrateLimitName != '\0' && - strcasecmp(bitrateLimitName, value) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding option 'limit' " - << "with new value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Overriding option 'limit' " - << "with new value '" << value << "'.\n"; - } - - if (ParseBitrateOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify 'limit' " - << "option in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify 'limit' " - << "option in string '" << value << "'.\n"; - - return -1; - } - } - - } - else if (strcasecmp(name, "render") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - useRender = ValidateArg("remote", name, value); - } - - } - else if (strcasecmp(name, "taint") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - useTaint = ValidateArg("remote", name, value); - } - - } - else if (strcasecmp(name, "type") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - if (strcasecmp(value, "default") == 0) - { - *sessionType = '\0'; - } - else - { - strncpy(sessionType, value, DEFAULT_STRING_LENGTH - 1); - } - } - - hasType = 1; - } - else if (strcasecmp(name, "strict") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - useStrict = ValidateArg("remote", name, value); - } - - } - else if (strcasecmp(name, "shseg") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else if (ParseShmemOption(value) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't identify size of shared memory " - << "segment in string '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify size of shared memory " - << "segment in string '" << value << "'.\n"; - - return -1; - } - - } - else if (strcasecmp(name, "delta") == 0) - { - if (control -> ProxyMode == proxy_client) - { - PrintOptionIgnored("remote", name, value); - } - else - { - control -> RemoteDeltaCompression = ValidateArg("remote", name, value); - - // - // Follow for delta compression the - // same settings as the client proxy. - // - - control -> LocalDeltaCompression = control -> RemoteDeltaCompression; - } - - hasDelta = 1; - } - else if (strcasecmp(name, "stream") == 0) - { - // - // If remote side didn't choose its own - // stream compression level then assume - // local settings. - // - - if (strcasecmp(value, "default") == 0) - { - // - // This applies only at client side. - // - - control -> RemoteStreamCompression = - control -> LocalStreamCompression; - - control -> RemoteStreamCompressionLevel = - control -> LocalStreamCompressionLevel; - } - else - { - control -> RemoteStreamCompressionLevel = ValidateArg("remote", name, value); - - if (control -> RemoteStreamCompressionLevel > 0) - { - control -> RemoteStreamCompression = 1; - } - else - { - control -> RemoteStreamCompression = 0; - } - - if (control -> LocalStreamCompressionLevel < 0) - { - control -> LocalStreamCompressionLevel = ValidateArg("remote", name, value); - - if (control -> LocalStreamCompressionLevel > 0) - { - control -> LocalStreamCompression = 1; - } - else - { - control -> LocalStreamCompression = 0; - } - } - } - - hasStream = 1; - } - else if (strcasecmp(name, "data") == 0) - { - // - // Apply the same to data compression level. - // - - if (strcasecmp(value, "default") == 0) - { - control -> RemoteDataCompression = - control -> LocalDataCompression; - - control -> RemoteDataCompressionLevel = - control -> LocalDataCompressionLevel; - } - else - { - control -> RemoteDataCompressionLevel = ValidateArg("remote", name, value); - - if (control -> RemoteDataCompressionLevel > 0) - { - control -> RemoteDataCompression = 1; - } - else - { - control -> RemoteDataCompression = 0; - } - - if (control -> LocalDataCompressionLevel < 0) - { - control -> LocalDataCompressionLevel = ValidateArg("remote", name, value); - - if (control -> LocalDataCompressionLevel > 0) - { - control -> LocalDataCompression = 1; - } - else - { - control -> LocalDataCompression = 0; - } - } - } - - hasData = 1; - } - else if (strcasecmp(name, "flush") == 0) - { - // - // This option has no effect in recent - // versions. - // - - #ifdef DEBUG - *logofs << "Loop: Ignoring obsolete remote option '" - << name << "' with value '" << value - << "'.\n" << logofs_flush; - #endif - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring unknown remote option '" - << name << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring unknown remote option '" - << name << "' with value '" << value << "'.\n"; - } - - name = strtok(NULL, "="); - - } // End of while (name) ... - - // - // If we are client side, we need remote 'stream' - // and 'data' options. If we are server, we need - // all the above plus 'link' and some others. - // - - char missing[DEFAULT_STRING_LENGTH]; - - *missing = '\0'; - - if (control -> ProxyMode == proxy_client) - { - if (hasStream == 0) - { - strcpy(missing, "stream"); - } - else if (hasData == 0) - { - strcpy(missing, "data"); - } - } - else - { - // - // Don't complain if the optional 'flush', - // 'render' and 'taint' options are not - // provided. - // - - if (hasLink == 0) - { - strcpy(missing, "link"); - } - else if (hasCache == 0) - { - strcpy(missing, "cache"); - } - else if (hasPack == 0) - { - strcpy(missing, "pack"); - } - else if (hasDelta == 0) - { - strcpy(missing, "delta"); - } - else if (hasStream == 0) - { - strcpy(missing, "stream"); - } - else if (hasData == 0) - { - strcpy(missing, "data"); - } - else if (hasType == 0) - { - strcpy(missing, "type"); - } - else if (hasImages == 0) - { - strcpy(missing, "images"); - } - } - - if (WE_PROVIDE_CREDENTIALS == 0) - { - // - // Can be that user doesn't have requested to - // check the authorization cookie provided by - // the connecting peer. - // - - if (hasCookie == 0 && *authCookie != '\0') - { - strcpy(missing, "cookie"); - } - } - - if (*missing != '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! The remote peer didn't specify the option '" - << missing << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": The remote peer didn't specify the option '" - << missing << "'.\n"; - - return -1; - } - - return 1; -} - -// -// Parse the cookie provided by the NX proxy -// connection forwarder. -// - -int ParseForwarderOptions(char *opts) -{ - #ifdef TEST - *logofs << "Loop: Going to parse the forwarder options " - << "string '" << opts << "'.\n" - << logofs_flush; - #endif - - char *name; - char *value; - - int hasCookie = 0; - - // - // Get rid of the terminating space. - // - - if (*(opts + strlen(opts) - 1) == ' ') - { - *(opts + strlen(opts) - 1) = '\0'; - } - - name = strtok(opts, "="); - - while (name) - { - value = strtok(NULL, ","); - - if (CheckArg("forwarder", name, value) < 0) - { - return -1; - } - - if (strcasecmp(name, "cookie") == 0) - { - if (strncasecmp(authCookie, value, strlen(authCookie)) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! The NX forwarder cookie '" << value - << "' doesn't match '" << authCookie << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": The NX forwarder cookie '" << value - << "' doesn't match '" << authCookie << "'.\n"; - - return -1; - } - - hasCookie = 1; - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring unknown forwarder option '" - << name << "' with value '" << value << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring unknown forwarder option '" - << name << "' with value '" << value << "'.\n"; - } - - name = strtok(NULL, "="); - - } // End of while (name) ... - - if (hasCookie == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! The NX forwarder didn't provide " - << "the authentication cookie.\n" << logofs_flush; - #endif - - cerr << "Error" << ": The NX forwarder didn't provide " - << "the authentication cookie.\n"; - - return -1; - } - - return 1; -} - -int SetCore() -{ - #ifdef COREDUMPS - - rlimit rlim; - - if (getrlimit(RLIMIT_CORE, &rlim)) - { - #ifdef TEST - *logofs << "Loop: Cannot read RLIMIT_CORE. Error is '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - return -1; - } - - if (rlim.rlim_cur < rlim.rlim_max) - { - rlim.rlim_cur = rlim.rlim_max; - - if (setrlimit(RLIMIT_CORE, &rlim)) - { - #ifdef TEST - *logofs << "Loop: Cannot set RLIMIT_CORE. Error is '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - return -2; - } - } - - #ifdef TEST - *logofs << "Loop: RLIMIT_CORE is "<< rlim.rlim_max - << ".\n" << logofs_flush; - #endif - - #endif // #ifdef COREDUMPS - - return 1; -} - -char *GetLastCache(char *listBuffer, const char *searchPath) -{ - if (listBuffer == NULL || searchPath == NULL || - strncmp(listBuffer, "cachelist=", strlen("cachelist=")) != 0) - { - #ifdef TEST - *logofs << "Loop: Invalid parameters '" << listBuffer << "' and '" - << (searchPath != NULL ? searchPath : "") - << "'. Can't select any cache.\n" << logofs_flush; - #endif - - return NULL; - } - - char *selectedName = new char[MD5_LENGTH * 2 + 3]; - - *selectedName = '\0'; - - const char *localPrefix; - const char *remotePrefix; - - if (control -> ProxyMode == proxy_client) - { - localPrefix = "C-"; - remotePrefix = "S-"; - } - else - { - localPrefix = "S-"; - remotePrefix = "C-"; - } - - // - // Get rid of prefix. - // - - listBuffer += strlen("cachelist="); - - char *fileName; - - fileName = strtok(listBuffer, ","); - - // - // It is "/path/to/file" + "/" + "C-" + 32 + "\0". - // - - char fullPath[strlen(searchPath) + MD5_LENGTH * 2 + 4]; - - time_t selectedTime = 0; - - struct stat fileStat; - - while (fileName) - { - if (strncmp(fileName, "none", strlen("none")) == 0) - { - #ifdef TEST - *logofs << "Loop: No cache files seem to be available.\n" - << logofs_flush; - #endif - - delete [] selectedName; - - return NULL; - } - else if (strlen(fileName) != MD5_LENGTH * 2 + 2 || - strncmp(fileName, remotePrefix, 2) != 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Bad cache file name '" - << fileName << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Bad cache file name '" - << fileName << "'.\n"; - - delete [] selectedName; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Parsing remote cache name '" - << fileName << "'.\n" << logofs_flush; - #endif - - // - // Prefix, received as "S-", becomes - // "C-" and viceversa. - // - - *fileName = *localPrefix; - - strcpy(fullPath, searchPath); - strcat(fullPath, "/"); - strcat(fullPath, fileName); - - if (stat(fullPath, &fileStat) == 0) - { - #ifdef TEST - *logofs << "Loop: Found a matching cache '" - << fullPath << "'.\n" << logofs_flush; - #endif - - if (fileStat.st_mtime >= selectedTime) - { - strcpy(selectedName, fileName); - - selectedTime = fileStat.st_mtime; - } - } - #ifdef TEST - else - { - *logofs << "Loop: Can't get stats of file '" - << fullPath << "'.\n" << logofs_flush; - } - #endif - - fileName = strtok(NULL, ","); - } - - if (*selectedName != '\0') - { - return selectedName; - } - else - { - delete [] selectedName; - - return NULL; - } -} - -char *GetTempPath() -{ - if (*tempDir == '\0') - { - // - // Check the NX_TEMP environment, first, - // then the TEMP variable. - // - - const char *tempEnv = getenv("NX_TEMP"); - - if (tempEnv == NULL || *tempEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_TEMP.\n" - << logofs_flush; - #endif - - tempEnv = getenv("TEMP"); - - if (tempEnv == NULL || *tempEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for TEMP.\n" - << logofs_flush; - #endif - - tempEnv = "/tmp"; - } - } - - if (strlen(tempEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "temporary directory '" << tempEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "temporary directory '" << tempEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(tempDir, tempEnv); - - #ifdef TEST - *logofs << "Loop: Assuming temporary NX directory '" - << tempDir << "'.\n" << logofs_flush; - #endif - } - - char *tempPath = new char[strlen(tempDir) + 1]; - - if (tempPath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the temp path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the temp path.\n"; - - HandleCleanup(); - } - - strcpy(tempPath, tempDir); - - return tempPath; -} - -char *GetClientPath() -{ - if (*clientDir == '\0') - { - // - // Check the NX_CLIENT environment. - // - - const char *clientEnv = getenv("NX_CLIENT"); - - if (clientEnv == NULL || *clientEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_CLIENT.\n" - << logofs_flush; - #endif - - // - // Try to guess the location of the client. - // - - clientEnv = "/usr/NX/bin/nxclient"; - - #ifdef __APPLE__ - - clientEnv = "/Applications/NX Client for OSX.app/Contents/MacOS/nxclient"; - - #endif - - #ifdef __CYGWIN32__ - - clientEnv = "C:\\Program Files\\NX Client for Windows\\nxclient"; - - #endif - } - - if (strlen(clientEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "client directory '" << clientEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "client directory '" << clientEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(clientDir, clientEnv); - - #ifdef TEST - *logofs << "Loop: Assuming NX client location '" - << clientDir << "'.\n" << logofs_flush; - #endif - } - - char *clientPath = new char[strlen(clientDir) + 1]; - - if (clientPath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the client path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the client path.\n"; - - HandleCleanup(); - } - - strcpy(clientPath, clientDir); - - return clientPath; -} - -char *GetSystemPath() -{ - if (*systemDir == '\0') - { - // - // Check the NX_SYSTEM environment. - // - - const char *systemEnv = getenv("NX_SYSTEM"); - - if (systemEnv == NULL || *systemEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_SYSTEM.\n" - << logofs_flush; - #endif - - systemEnv = "/usr/NX"; - } - - if (strlen(systemEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "system directory '" << systemEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "system directory '" << systemEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(systemDir, systemEnv); - - #ifdef TEST - *logofs << "Loop: Assuming system NX directory '" - << systemDir << "'.\n" << logofs_flush; - #endif - } - - char *systemPath = new char[strlen(systemDir) + 1]; - - if (systemPath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the system path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the system path.\n"; - - HandleCleanup(); - } - - strcpy(systemPath, systemDir); - - return systemPath; -} - -char *GetHomePath() -{ - if (*homeDir == '\0') - { - // - // Check the NX_HOME environment. - // - - const char *homeEnv = getenv("NX_HOME"); - - if (homeEnv == NULL || *homeEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_HOME.\n" - << logofs_flush; - #endif - - homeEnv = getenv("HOME"); - - if (homeEnv == NULL || *homeEnv == '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! No environment for HOME.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": No environment for HOME.\n"; - - HandleCleanup(); - } - } - - if (strlen(homeEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "home directory '" << homeEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "home directory '" << homeEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(homeDir, homeEnv); - - #ifdef TEST - *logofs << "Loop: Assuming NX user's home directory '" - << homeDir << "'.\n" << logofs_flush; - #endif - } - - char *homePath = new char[strlen(homeDir) + 1]; - - if (homePath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the home path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the home path.\n"; - - HandleCleanup(); - } - - strcpy(homePath, homeDir); - - return homePath; -} - -char *GetRootPath() -{ - if (*rootDir == '\0') - { - // - // Check the NX_ROOT environment. - // - - const char *rootEnv = getenv("NX_ROOT"); - - if (rootEnv == NULL || *rootEnv == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No environment for NX_ROOT.\n" - << logofs_flush; - #endif - - // - // We will determine the root NX directory - // based on the NX_HOME or HOME directory - // settings. - // - - const char *homeEnv = GetHomePath(); - - if (strlen(homeEnv) > DEFAULT_STRING_LENGTH - - strlen("/.nx") - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "home directory '" << homeEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "home directory '" << homeEnv - << "'.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Assuming NX root directory in " - << "the user's home '" << homeEnv - << "'.\n" << logofs_flush; - #endif - - strcpy(rootDir, homeEnv); - strcat(rootDir, "/.nx"); - - delete [] homeEnv; - - // - // Create the NX root directory. - // - - struct stat dirStat; - - if ((stat(rootDir, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(rootDir, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" - << rootDir << ". Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" - << rootDir << ". Error is " << EGET() << " '" - << ESTR() << "'.\n"; - - HandleCleanup(); - } - } - } - else - { - if (strlen(rootEnv) > DEFAULT_STRING_LENGTH - 1) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value for the NX " - << "root directory '" << rootEnv - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value for the NX " - << "root directory '" << rootEnv - << "'.\n"; - - HandleCleanup(); - } - - strcpy(rootDir, rootEnv); - } - - #ifdef TEST - *logofs << "Loop: Assuming NX root directory '" - << rootDir << "'.\n" << logofs_flush; - #endif - } - - char *rootPath = new char[strlen(rootDir) + 1]; - - if (rootPath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't allocate memory " - << "for the root path.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the root path.\n"; - - HandleCleanup(); - } - - strcpy(rootPath, rootDir); - - return rootPath; -} - -char *GetCachePath() -{ - char *rootPath = GetRootPath(); - - char *cachePath; - - if (*sessionType != '\0') - { - cachePath = new char[strlen(rootPath) + strlen("/cache-") + - strlen(sessionType) + 1]; - } - else - { - cachePath = new char[strlen(rootPath) + strlen("/cache") + 1]; - } - - strcpy(cachePath, rootPath); - - if (*sessionType != '\0') - { - strcat(cachePath, "/cache-"); - - strcat(cachePath, sessionType); - } - else - { - strcat(cachePath, "/cache"); - } - - // - // Create the cache directory if needed. - // - - struct stat dirStat; - - if ((stat(cachePath, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(cachePath, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" << cachePath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" << cachePath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] rootPath; - delete [] cachePath; - - return NULL; - } - } - - delete [] rootPath; - - return cachePath; -} - -char *GetImagesPath() -{ - char *rootPath = GetRootPath(); - - char *imagesPath = new char[strlen(rootPath) + strlen("/images") + 1]; - - strcpy(imagesPath, rootPath); - - strcat(imagesPath, "/images"); - - // - // Create the cache directory if needed. - // - - struct stat dirStat; - - if ((stat(imagesPath, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(imagesPath, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" << imagesPath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" << imagesPath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] rootPath; - delete [] imagesPath; - - return NULL; - } - } - - // - // Create 16 directories in the path to - // hold the images whose name begins with - // the corresponding hexadecimal digit. - // - - char *digitPath = new char[strlen(imagesPath) + 5]; - - strcpy(digitPath, imagesPath); - - // - // Image paths have format "[path][/I-c][\0]", - // where c is the first digit of the checksum. - // - - for (char digit = 0; digit < 16; digit++) - { - sprintf(digitPath + strlen(imagesPath), "/I-%01X", digit); - - if ((stat(digitPath, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(digitPath, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" << digitPath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" << digitPath - << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] rootPath; - delete [] imagesPath; - delete [] digitPath; - - return NULL; - } - } - } - - delete [] rootPath; - delete [] digitPath; - - return imagesPath; -} - -char *GetSessionPath() -{ - if (*sessionDir == '\0') - { - char *rootPath = GetRootPath(); - - strcpy(sessionDir, rootPath); - - if (control -> ProxyMode == proxy_client) - { - strcat(sessionDir, "/C-"); - } - else - { - strcat(sessionDir, "/S-"); - } - - if (*sessionId == '\0') - { - char port[DEFAULT_STRING_LENGTH]; - - sprintf(port, "%d", proxyPort); - - strcpy(sessionId, port); - } - - strcat(sessionDir, sessionId); - - struct stat dirStat; - - if ((stat(sessionDir, &dirStat) == -1) && (EGET() == ENOENT)) - { - if (mkdir(sessionDir, 0700) < 0 && (EGET() != EEXIST)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't create directory '" << sessionDir - << ". Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create directory '" << sessionDir - << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; - - delete [] rootPath; - - return NULL; - } - } - - #ifdef TEST - *logofs << "Loop: Root of NX session is '" << sessionDir - << "'.\n" << logofs_flush; - #endif - - delete [] rootPath; - } - - char *sessionPath = new char[strlen(sessionDir) + 1]; - - strcpy(sessionPath, sessionDir); - - return sessionPath; -} - -// -// Identify requested link characteristics -// and set control parameters accordingly. -// - -int ParseLinkOption(const char *opt) -{ - // - // Normalize the user input. - // - - if (strcasecmp(opt, "modem") == 0 || - strcasecmp(opt, "33k") == 0 || - strcasecmp(opt, "56k") == 0) - { - strcpy(linkSpeedName, "MODEM"); - } - else if (strcasecmp(opt, "isdn") == 0 || - strcasecmp(opt, "64k") == 0 || - strcasecmp(opt, "128k") == 0) - { - strcpy(linkSpeedName, "ISDN"); - } - else if (strcasecmp(opt, "adsl") == 0 || - strcasecmp(opt, "256k") == 0 || - strcasecmp(opt, "640k") == 0) - { - strcpy(linkSpeedName, "ADSL"); - } - else if (strcasecmp(opt, "wan") == 0 || - strcasecmp(opt, "1m") == 0 || - strcasecmp(opt, "2m") == 0 || - strcasecmp(opt, "34m") == 0) - { - strcpy(linkSpeedName, "WAN"); - } - else if (strcasecmp(opt, "lan") == 0 || - strcasecmp(opt, "10m") == 0 || - strcasecmp(opt, "100m") == 0 || - strcasecmp(opt, "local") == 0) - { - strcpy(linkSpeedName, "LAN"); - } - - if (strcasecmp(linkSpeedName, "modem") != 0 && - strcasecmp(linkSpeedName, "isdn") != 0 && - strcasecmp(linkSpeedName, "adsl") != 0 && - strcasecmp(linkSpeedName, "wan") != 0 && - strcasecmp(linkSpeedName, "lan") != 0) - { - return -1; - } - - return 1; -} - -int ParsePackOption(const char *opt) -{ - #ifdef DEBUG - *logofs << "Loop: Pack method is " << packMethod - << " quality is " << packQuality << ".\n" - << logofs_flush; - #endif - - #ifdef DEBUG - *logofs << "Loop: Parsing pack method '" << opt - << "'.\n" << logofs_flush; - #endif - - if (strcasecmp(opt, "0") == 0 || - strcasecmp(opt, "none") == 0 || - strcasecmp(opt, "nopack") == 0 || - strcasecmp(opt, "no-pack") == 0) - { - packMethod = PACK_NONE; - } - else if (strcasecmp(opt, "8") == 0) - { - packMethod = PACK_MASKED_8_COLORS; - } - else if (strcasecmp(opt, "64") == 0) - { - packMethod = PACK_MASKED_64_COLORS; - } - else if (strcasecmp(opt, "256") == 0) - { - packMethod = PACK_MASKED_256_COLORS; - } - else if (strcasecmp(opt, "512") == 0) - { - packMethod = PACK_MASKED_512_COLORS; - } - else if (strcasecmp(opt, "4k") == 0) - { - packMethod = PACK_MASKED_4K_COLORS; - } - else if (strcasecmp(opt, "32k") == 0) - { - packMethod = PACK_MASKED_32K_COLORS; - } - else if (strcasecmp(opt, "64k") == 0) - { - packMethod = PACK_MASKED_64K_COLORS; - } - else if (strcasecmp(opt, "256k") == 0) - { - packMethod = PACK_MASKED_256K_COLORS; - } - else if (strcasecmp(opt, "2m") == 0) - { - packMethod = PACK_MASKED_2M_COLORS; - } - else if (strcasecmp(opt, "16m") == 0) - { - packMethod = PACK_MASKED_16M_COLORS; - } - else if (strncasecmp(opt, "8-jpeg", strlen("8-jpeg")) == 0) - { - packMethod = PACK_JPEG_8_COLORS; - } - else if (strncasecmp(opt, "64-jpeg", strlen("64-jpeg")) == 0) - { - packMethod = PACK_JPEG_64_COLORS; - } - else if (strncasecmp(opt, "256-jpeg", strlen("256-jpeg")) == 0) - { - packMethod = PACK_JPEG_256_COLORS; - } - else if (strncasecmp(opt, "512-jpeg", strlen("512-jpeg")) == 0) - { - packMethod = PACK_JPEG_512_COLORS; - } - else if (strncasecmp(opt, "4k-jpeg", strlen("4k-jpeg")) == 0) - { - packMethod = PACK_JPEG_4K_COLORS; - } - else if (strncasecmp(opt, "32k-jpeg", strlen("32k-jpeg")) == 0) - { - packMethod = PACK_JPEG_32K_COLORS; - } - else if (strncasecmp(opt, "64k-jpeg", strlen("64k-jpeg")) == 0) - { - packMethod = PACK_JPEG_64K_COLORS; - } - else if (strncasecmp(opt, "256k-jpeg", strlen("256k-jpeg")) == 0) - { - packMethod = PACK_JPEG_256K_COLORS; - } - else if (strncasecmp(opt, "2m-jpeg", strlen("2m-jpeg")) == 0) - { - packMethod = PACK_JPEG_2M_COLORS; - } - else if (strncasecmp(opt, "16m-jpeg", strlen("16m-jpeg")) == 0) - { - packMethod = PACK_JPEG_16M_COLORS; - } - else if (strncasecmp(opt, "8-png", strlen("8-png")) == 0) - { - packMethod = PACK_PNG_8_COLORS; - } - else if (strncasecmp(opt, "64-png", strlen("64-png")) == 0) - { - packMethod = PACK_PNG_64_COLORS; - } - else if (strncasecmp(opt, "256-png", strlen("256-png")) == 0) - { - packMethod = PACK_PNG_256_COLORS; - } - else if (strncasecmp(opt, "512-png", strlen("512-png")) == 0) - { - packMethod = PACK_PNG_512_COLORS; - } - else if (strncasecmp(opt, "4k-png", strlen("4k-png")) == 0) - { - packMethod = PACK_PNG_4K_COLORS; - } - else if (strncasecmp(opt, "32k-png", strlen("32k-png")) == 0) - { - packMethod = PACK_PNG_32K_COLORS; - } - else if (strncasecmp(opt, "64k-png", strlen("64k-png")) == 0) - { - packMethod = PACK_PNG_64K_COLORS; - } - else if (strncasecmp(opt, "256k-png", strlen("256k-png")) == 0) - { - packMethod = PACK_PNG_256K_COLORS; - } - else if (strncasecmp(opt, "2m-png", strlen("2m-png")) == 0) - { - packMethod = PACK_PNG_2M_COLORS; - } - else if (strncasecmp(opt, "16m-png", strlen("16m-png")) == 0) - { - packMethod = PACK_PNG_16M_COLORS; - } - else if (strncasecmp(opt, "16m-rgb", strlen("16m-rgb")) == 0 || - strncasecmp(opt, "rgb", strlen("rgb")) == 0) - { - packMethod = PACK_RGB_16M_COLORS; - } - else if (strncasecmp(opt, "16m-rle", strlen("16m-rle")) == 0 || - strncasecmp(opt, "rle", strlen("rle")) == 0) - { - packMethod = PACK_RLE_16M_COLORS; - } - else if (strncasecmp(opt, "16m-bitmap", strlen("16m-bitmap")) == 0 || - strncasecmp(opt, "bitmap", strlen("bitmap")) == 0) - { - packMethod = PACK_BITMAP_16M_COLORS; - } - else if (strncasecmp(opt, "lossy", strlen("lossy")) == 0) - { - packMethod = PACK_LOSSY; - } - else if (strncasecmp(opt, "lossless", strlen("lossless")) == 0) - { - packMethod = PACK_LOSSLESS; - } - else if (strncasecmp(opt, "adaptive", strlen("adaptive")) == 0) - { - packMethod = PACK_ADAPTIVE; - } - else - { - return -1; - } - - if (packMethod == PACK_NONE) - { - strcpy(packMethodName, "none"); - } - else - { - strcpy(packMethodName, opt); - } - - if (packMethod == PACK_RGB_16M_COLORS || - packMethod == PACK_RLE_16M_COLORS || - packMethod == PACK_BITMAP_16M_COLORS || - (packMethod >= PACK_JPEG_8_COLORS && - packMethod <= PACK_JPEG_16M_COLORS) || - (packMethod >= PACK_PNG_8_COLORS && - packMethod <= PACK_PNG_16M_COLORS) || - packMethod == PACK_LOSSY || - packMethod == PACK_LOSSLESS || - packMethod == PACK_ADAPTIVE) - { - const char *dash = strrchr(opt, '-'); - - if (dash != NULL && strlen(dash) == 2 && - *(dash + 1) >= '0' && *(dash + 1) <= '9') - { - packQuality = atoi(dash + 1); - - #ifdef DEBUG - *logofs << "Loop: Using pack quality '" - << packQuality << "'.\n" << logofs_flush; - #endif - } - } - else - { - packQuality = 0; - } - - return 1; -} - -int ParsePackMethod(const int method, const int quality) -{ - switch (method) - { - case PACK_NONE: - { - strcpy(packMethodName, "none"); - - break; - } - case PACK_MASKED_8_COLORS: - { - strcpy(packMethodName, "8"); - - break; - } - case PACK_MASKED_64_COLORS: - { - strcpy(packMethodName, "64"); - - break; - } - case PACK_MASKED_256_COLORS: - { - strcpy(packMethodName, "256"); - - break; - } - case PACK_MASKED_512_COLORS: - { - strcpy(packMethodName, "512"); - - break; - } - case PACK_MASKED_4K_COLORS: - { - strcpy(packMethodName, "4k"); - - break; - } - case PACK_MASKED_32K_COLORS: - { - strcpy(packMethodName, "32k"); - - break; - } - case PACK_MASKED_64K_COLORS: - { - strcpy(packMethodName, "64k"); - - break; - } - case PACK_MASKED_256K_COLORS: - { - strcpy(packMethodName, "256k"); - - break; - } - case PACK_MASKED_2M_COLORS: - { - strcpy(packMethodName, "2m"); - - break; - } - case PACK_MASKED_16M_COLORS: - { - strcpy(packMethodName, "16m"); - - break; - } - case PACK_JPEG_8_COLORS: - { - strcpy(packMethodName, "8-jpeg"); - - break; - } - case PACK_JPEG_64_COLORS: - { - strcpy(packMethodName, "64-jpeg"); - - break; - } - case PACK_JPEG_256_COLORS: - { - strcpy(packMethodName, "256-jpeg"); - - break; - } - case PACK_JPEG_512_COLORS: - { - strcpy(packMethodName, "512-jpeg"); - - break; - } - case PACK_JPEG_4K_COLORS: - { - strcpy(packMethodName, "4k-jpeg"); - - break; - } - case PACK_JPEG_32K_COLORS: - { - strcpy(packMethodName, "32k-jpeg"); - - break; - } - case PACK_JPEG_64K_COLORS: - { - strcpy(packMethodName, "64k-jpeg"); - - break; - } - case PACK_JPEG_256K_COLORS: - { - strcpy(packMethodName, "256k-jpeg"); - - break; - } - case PACK_JPEG_2M_COLORS: - { - strcpy(packMethodName, "2m-jpeg"); - - break; - } - case PACK_JPEG_16M_COLORS: - { - strcpy(packMethodName, "16m-jpeg"); - - break; - } - case PACK_PNG_8_COLORS: - { - strcpy(packMethodName, "8-png"); - - break; - } - case PACK_PNG_64_COLORS: - { - strcpy(packMethodName, "64-png"); - - break; - } - case PACK_PNG_256_COLORS: - { - strcpy(packMethodName, "256-png"); - - break; - } - case PACK_PNG_512_COLORS: - { - strcpy(packMethodName, "512-png"); - - break; - } - case PACK_PNG_4K_COLORS: - { - strcpy(packMethodName, "4k-png"); - - break; - } - case PACK_PNG_32K_COLORS: - { - strcpy(packMethodName, "32k-png"); - - break; - } - case PACK_PNG_64K_COLORS: - { - strcpy(packMethodName, "64k-png"); - - break; - } - case PACK_PNG_256K_COLORS: - { - strcpy(packMethodName, "256k-png"); - - break; - } - case PACK_PNG_2M_COLORS: - { - strcpy(packMethodName, "2m-png"); - - break; - } - case PACK_PNG_16M_COLORS: - { - strcpy(packMethodName, "16m-png"); - - break; - } - case PACK_RGB_16M_COLORS: - { - strcpy(packMethodName, "16m-rgb"); - - break; - } - case PACK_RLE_16M_COLORS: - { - strcpy(packMethodName, "16m-rle"); - - break; - } - case PACK_BITMAP_16M_COLORS: - { - strcpy(packMethodName, "16m-bitmap"); - - break; - } - case PACK_LOSSY: - { - strcpy(packMethodName, "lossy"); - - break; - } - case PACK_LOSSLESS: - { - strcpy(packMethodName, "lossless"); - - break; - } - case PACK_ADAPTIVE: - { - strcpy(packMethodName, "adaptive"); - - break; - } - default: - { - return -1; - } - } - - if (quality < 0 || quality > 9) - { - return -1; - } - - if (packMethod == PACK_RGB_16M_COLORS || - packMethod == PACK_RLE_16M_COLORS || - packMethod == PACK_BITMAP_16M_COLORS || - (packMethod >= PACK_JPEG_8_COLORS && - packMethod <= PACK_JPEG_16M_COLORS) || - (packMethod >= PACK_PNG_8_COLORS && - packMethod <= PACK_PNG_16M_COLORS) || - packMethod == PACK_LOSSY || - packMethod == PACK_LOSSLESS || - packMethod == PACK_ADAPTIVE) - { - sprintf(packMethodName + strlen(packMethodName), - "-%d", quality); - } - - packMethod = method; - packQuality = quality; - - control -> PackMethod = packMethod; - control -> PackQuality = packQuality; - - return 1; -} - -int SetDirectories() -{ - // - // Determine the location of the user's NX - // directory and the other relevant paths. - // The functions below will check the pa- - // rameters passed to the program and will - // query the environment, if needed. - // - - control -> HomePath = GetHomePath(); - control -> RootPath = GetRootPath(); - control -> SystemPath = GetSystemPath(); - control -> TempPath = GetTempPath(); - control -> ClientPath = GetClientPath(); - - return 1; -} - -int SetLogs() -{ - // - // So far we used stderr (or stdout under - // WIN32). Now use the files selected by - // the user. - // - - if (*statsFileName == '\0') - { - strcpy(statsFileName, "stats"); - - #ifdef TEST - *logofs << "Loop: Assuming default statistics file '" - << statsFileName << "'.\n" << logofs_flush; - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Name selected for statistics is '" - << statsFileName << "'.\n" << logofs_flush; - } - #endif - - if (OpenLogFile(statsFileName, statofs) < 0) - { - HandleCleanup(); - } - - #ifndef MIXED - - if (*errorsFileName == '\0') - { - strcpy(errorsFileName, "errors"); - - #ifdef TEST - *logofs << "Loop: Assuming default log file name '" - << errorsFileName << "'.\n" << logofs_flush; - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Name selected for log file is '" - << errorsFileName << "'.\n" << logofs_flush; - } - #endif - - // - // Share the bebug output with the nxssh binder - // process. The file must be made writable by - // everybody because the nxssh process is run by - // nxserver as the nx user. - // - - #ifdef BINDER - - strcpy(errorsFileName, "/tmp/errors"); - - ostream *tmpfs = new ofstream(errorsFileName, ios::out); - - delete tmpfs; - - chmod(errorsFileName, S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP | S_IROTH | S_IWOTH); - - #endif - - if (OpenLogFile(errorsFileName, logofs) < 0) - { - HandleCleanup(); - } - - // - // By default the session log is the standard error - // of the process. It is anyway required to set the - // option when running inside SSH, otherwise the - // output will go to the same file as the SSH log, - // depending where the NX client has redirected the - // output. - // - - if (*sessionFileName != '\0') - { - #ifdef TEST - *logofs << "Loop: Name selected for session file is '" - << sessionFileName << "'.\n" << logofs_flush; - #endif - - if (errofs != NULL) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Unexpected value for stream errofs.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Unexpected value for stream errofs.\n"; - } - - if (errsbuf != NULL) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Unexpected value for buffer errsbuf.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Unexpected value for buffer errsbuf.\n"; - } - - errofs = NULL; - errsbuf = NULL; - - if (OpenLogFile(sessionFileName, errofs) < 0) - { - HandleCleanup(); - } - - // - // Redirect the standard error to the file. - // - - errsbuf = cerr.rdbuf(errofs -> rdbuf()); - } - - #endif - - return 1; -} - -int SetPorts() -{ - // - // Depending on the proxy side, we need to determine on which - // port to listen for the given protocol or to which port we - // will have to forward the connection. Three possibilities - // are given for each supported protocol: - // - // Port <= 0: Disable port forwarding. - // Port == 1: Use the default port. - // Port > 1: Use the specified port. - // - // At the connectiong side the user should always explicitly - // set the ports where the connections will be forwarded. This - // is both for security reasons and because, when running both - // proxies on the same host, there is a concrete possibility - // that, by using the default ports, the connection will be - // forwarded to the same port where the peer proxy is listen- - // ing, causing a loop. - // - - useCupsSocket = 0; - if (cupsPort.enabled()) { - if (control -> ProxyMode == proxy_client) { - cupsPort.setDefaultTCPPort(DEFAULT_NX_CUPS_PORT_OFFSET + proxyPort); - useCupsSocket = 1; - } - else - cupsPort.setDefaultTCPPort(631); - } - -#ifdef TEST - *logofs << "Loop: cups port: " << cupsPort << "\n" - << logofs_flush; -#endif - - useAuxSocket = 0; - if (auxPort.enabled()) { - if (control -> ProxyMode == proxy_client) { - auxPort.setDefaultTCPPort(DEFAULT_NX_AUX_PORT_OFFSET + proxyPort); - useAuxSocket = 1; - } - else { - auxPort.setDefaultTCPPort(1); - - if (auxPort.getTCPPort() != 1) { - -#ifdef WARNING - *logofs << "Loop: WARNING! Overriding auxiliary X11 " - << "port with new value '" << 1 << "'.\n" - << logofs_flush; -#endif - - cerr << "Warning" << ": Overriding auxiliary X11 " - << "port with new value '" << 1 << "'.\n"; - - auxPort.setSpec("1"); - } - } - } - -#ifdef TEST - *logofs << "Loop: aux port: " << auxPort << "\n" - << logofs_flush; -#endif - - useSmbSocket = 0; - if (smbPort.enabled()) { - if (control -> ProxyMode == proxy_client) { - auxPort.setDefaultTCPPort(DEFAULT_NX_SMB_PORT_OFFSET + proxyPort); - useAuxSocket = 1; - } - else - auxPort.setDefaultTCPPort(139); - } - - -#ifdef TEST - *logofs << "Loop: smb port: " << smbPort << "\n" - << logofs_flush; -#endif - - useMediaSocket = 0; - if (mediaPort.enabled()) { - if (control -> ProxyMode == proxy_client) { - mediaPort.setDefaultTCPPort(DEFAULT_NX_MEDIA_PORT_OFFSET + proxyPort); - useMediaSocket = 1; - } - else if (mediaPort.getTCPPort() == 1) { -#ifdef PANIC - *logofs << "Loop: PANIC! No port specified for multimedia connections.\n" - << logofs_flush; -#endif - - cerr << "Error" << ": No port specified for multimedia connections.\n"; - - HandleCleanup(); - } - } - -#ifdef TEST - *logofs << "Loop: Using multimedia port '" << mediaPort - << "'.\n" << logofs_flush; -#endif - - useHttpSocket = 0; - if (httpPort.enabled()) { - if (control -> ProxyMode == proxy_client) { - httpPort.setDefaultTCPPort(DEFAULT_NX_HTTP_PORT_OFFSET + proxyPort); - useHttpSocket = 1; - } - else - httpPort.setDefaultTCPPort(80); - } - -#ifdef TEST - *logofs << "Loop: Using HTTP port '" << httpPort - << "'.\n" << logofs_flush; -#endif - - if (ParseFontPath(fontPort) <= 0) - { - #ifdef TEST - *logofs << "Loop: Disabling font server connections.\n" - << logofs_flush; - #endif - - *fontPort = '\0'; - - useFontSocket = 0; - } - else - { - // - // We don't know yet if the remote proxy supports - // the font server connections. If needed, we will - // disable the font server connections at later - // time. - // - - if (control -> ProxyMode == proxy_server) - { - useFontSocket = 1; - } - else - { - useFontSocket = 0; - } - - #ifdef TEST - *logofs << "Loop: Using font server port '" << fontPort - << "'.\n" << logofs_flush; - #endif - } - - useSlaveSocket = 0; - if (slavePort.enabled()) { - useSlaveSocket = 1; - if (control -> ProxyMode == proxy_client) - slavePort.setDefaultTCPPort(DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET + proxyPort); - else - slavePort.setDefaultTCPPort(DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET + proxyPort); - } - -#ifdef TEST - *logofs << "Loop: Using slave port '" << slavePort - << "'.\n" << logofs_flush; -#endif - - return 1; -} - -int SetDescriptors() -{ - unsigned int limit = 0; - - #ifdef RLIMIT_NOFILE - - rlimit limits; - - if (getrlimit(RLIMIT_NOFILE, &limits) == 0) - { - if (limits.rlim_max == RLIM_INFINITY) - { - limit = 0; - } - else - { - limit = (unsigned int) limits.rlim_max; - } - } - - #endif - - #ifdef _SC_OPEN_MAX - - if (limit == 0) - { - limit = sysconf(_SC_OPEN_MAX); - } - - #endif - - #ifdef FD_SETSIZE - - if (limit > FD_SETSIZE) - { - limit = FD_SETSIZE; - } - - #endif - - #ifdef RLIMIT_NOFILE - - if (limits.rlim_cur < limit) - { - limits.rlim_cur = limit; - - setrlimit(RLIMIT_NOFILE, &limits); - } - - #endif - - if (limit == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Cannot determine number of available " - << "file descriptors.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot determine number of available " - << "file descriptors.\n"; - - return -1; - } - - return 1; -} - -// -// Find the directory containing the caches -// matching the session type. -// - -int SetCaches() -{ - if ((control -> PersistentCachePath = GetCachePath()) == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error getting or creating the cache path.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error getting or creating the cache path.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Path of cache files is '" << control -> PersistentCachePath - << "'.\n" << logofs_flush; - #endif - - return 1; -} - -// -// Initialize all configuration parameters. -// - -int SetParameters() -{ - // - // Find out the type of session. - // - - SetSession(); - - // - // Initialize the network and compression - // parameters according to the settings - // suggested by the user. - // - - SetLink(); - - // - // Set compression according to link speed. - // - - SetCompression(); - - // - // Be sure that we have a literal for current - // cache size. Value will reflect control's - // default unless we already parsed a 'cache' - // option. Server side has no control on size - // of cache but is informed at session nego- - // tiation about how much memory is going to - // be used. - // - - SetStorage(); - - // - // Set size of shared memory segments. - // - - SetShmem(); - - // - // Make adjustments to cache based - // on the pack method. - // - - SetPack(); - - // - // Set disk-based image cache. - // - - SetImages(); - - // - // Set CPU and bandwidth limits. - // - - SetLimits(); - - return 1; -} - -// -// According to session literal determine -// the type of traffic that is going to be -// transported. Literals should be better -// standardized in future NX versions. -// - -int SetSession() -{ - if (strncmp(sessionType, "agent", strlen("agent")) == 0 || - strncmp(sessionType, "desktop", strlen("desktop")) == 0 || - strncmp(sessionType, "rootless", strlen("rootless")) == 0 || - strncmp(sessionType, "console", strlen("console")) == 0 || - strncmp(sessionType, "default", strlen("default")) == 0 || - strncmp(sessionType, "gnome", strlen("gnome")) == 0 || - strncmp(sessionType, "kde", strlen("kde")) == 0 || - strncmp(sessionType, "cde", strlen("cde")) == 0 || - strncmp(sessionType, "xdm", strlen("xdm")) == 0) - { - control -> SessionMode = session_agent; - } - else if (strncmp(sessionType, "win", strlen("win")) == 0 || - strncmp(sessionType, "vnc", strlen("vnc")) == 0) - { - control -> SessionMode = session_agent; - } - else if (strncmp(sessionType, "shadow", strlen("shadow")) == 0) - { - control -> SessionMode = session_shadow; - } - else if (strncmp(sessionType, "proxy", strlen("proxy")) == 0 || - strncmp(sessionType, "application", strlen("application")) == 0 || - strncmp(sessionType, "raw", strlen("raw")) == 0) - { - control -> SessionMode = session_proxy; - } - else - { - // - // If the session type is not passed or - // it is not among the recognized strings, - // we assume that the proxy is connected - // to the agent. - // - - // - // Since ProtoStep8 (#issue 108) and also - // with older "unix-" sessions - // - - if (*sessionType != '\0') - { - #ifdef WARNING - *logofs << "Loop: WARNING! Unrecognized session type '" - << sessionType << "'. Assuming agent session.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Unrecognized session type '" - << sessionType << "'. Assuming agent session.\n"; - } - - control -> SessionMode = session_agent; - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Assuming session type '" - << DumpSession(control -> SessionMode) << "' with " - << "string '" << sessionType << "'.\n" - << logofs_flush; - #endif - - // - // By default the policy is immediate. Agents - // will set a different policy, if they like. - // Anyway we need to check if the user has - // provided a custom flush policy. - // - - if (usePolicy != -1) - { - if (usePolicy > 0) - { - control -> FlushPolicy = policy_deferred; - } - else - { - control -> FlushPolicy = policy_immediate; - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: WARNING! Forcing flush policy to '" - << DumpPolicy(control -> FlushPolicy) - << ".\n" << logofs_flush; - #endif - } - else - { - control -> FlushPolicy = policy_immediate; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting initial flush policy to '" - << DumpPolicy(control -> FlushPolicy) - << "'.\n" << logofs_flush; - #endif - } - - // - // Check if the proxy library is run inside - // another program providing encryption, as - // it is the case of the SSH client. - // - - if (useEncryption != -1) - { - if (useEncryption > 0) - { - control -> LinkEncrypted = 1; - } - else - { - control -> LinkEncrypted = 0; - } - } - - if (control -> LinkEncrypted == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Proxy running as part of an " - << "encrypting client.\n" - << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Assuming proxy running as a " - << "standalone program.\n" - << logofs_flush; - #endif - } - - // - // Check if the system administrator has - // enabled the respawn of the client at - // the end of session. - // - - if (control -> ProxyMode == proxy_server) - { - struct stat fileStat; - - char fileName[DEFAULT_STRING_LENGTH]; - - snprintf(fileName, DEFAULT_STRING_LENGTH - 1, - "%s/share/noexit", control -> SystemPath); - - *(fileName + DEFAULT_STRING_LENGTH - 1) = '\0'; - - if (stat(fileName, &fileStat) == 0) - { - #ifdef TEST - *logofs << "Loop: Enabling respawn of client at session shutdown.\n" - << logofs_flush; - #endif - - control -> EnableRestartOnShutdown = 1; - } - } - - return 1; -} - -int SetStorage() -{ - // - // If differential compression is disabled - // we don't need a cache at all. - // - - if (control -> LocalDeltaCompression == 0) - { - control -> ClientTotalStorageSize = 0; - control -> ServerTotalStorageSize = 0; - } - - // - // Set a a cache size literal. - // - - int size = control -> getUpperStorageSize(); - - if (size / 1024 > 0) - { - sprintf(cacheSizeName, "%dk", size / 1024); - } - else - { - sprintf(cacheSizeName, "%d", size); - } - - if (control -> ProxyMode == proxy_client) - { - control -> LocalTotalStorageSize = - control -> ClientTotalStorageSize; - - control -> RemoteTotalStorageSize = - control -> ServerTotalStorageSize; - } - else - { - control -> LocalTotalStorageSize = - control -> ServerTotalStorageSize; - - control -> RemoteTotalStorageSize = - control -> ClientTotalStorageSize; - } - - #ifdef DEBUG - *logofs << "Loop: Storage size limit is " - << control -> ClientTotalStorageSize - << " at client and " - << control -> ServerTotalStorageSize - << " at server.\n" - << logofs_flush; - #endif - - #ifdef DEBUG - *logofs << "Loop: Storage local limit set to " - << control -> LocalTotalStorageSize - << " remote limit set to " - << control -> RemoteTotalStorageSize - << ".\n" << logofs_flush; - #endif - - // - // Never reserve for split store more than - // half the memory available for messages. - // - - if (size > 0 && control -> - SplitTotalStorageSize > size / 2) - { - #ifdef TEST - *logofs << "Loop: Reducing size of split store to " - << size / 2 << " bytes.\n" - << logofs_flush; - #endif - - control -> SplitTotalStorageSize = size / 2; - } - - // - // Don't load render from persistent - // cache if extension is hidden or - // not supported by agent. - // - - if (control -> HideRender == 1) - { - #ifdef TEST - *logofs << "Loop: Not loading render extension " - << "from persistent cache.\n" - << logofs_flush; - #endif - - control -> PersistentCacheLoadRender = 0; - } - - return 1; -} - -int SetShmem() -{ - // - // If not set, adjust the size of the shared - // memory segment according to size of the - // message cache. - // - - if (*shsegSizeName == '\0') - { - int size = control -> getUpperStorageSize(); - - const int mega = 1048576; - - if (size > 0) - { - if (size <= 1 * mega) - { - size = 0; - } - else if (size <= 2 * mega) - { - size = 524288; - } - else if (size < 4 * mega) - { - size = 1048576; - } - else - { - size = size / 4; - } - - if (size > 4194304) - { - size = 4194304; - } - - control -> ShmemClientSize = size; - control -> ShmemServerSize = size; - } - else - { - // - // The delta compression is disabled. - // Use a default segment size of 2 MB. - // - - control -> ShmemServerSize = 2 * mega; - } - } - - // - // Client side shared memory support is - // not useful and not implemented. - // - - if (control -> ShmemServerSize >= 524288) - { - control -> ShmemServer = 1; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Set initial shared memory size " - << "to " << control -> ShmemServerSize - << " bytes.\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Disabled use of the shared memory " - << "extension.\n" << logofs_flush; - #endif - - control -> ShmemServer = 0; - } - - // For android, no shared memory available - control -> ShmemServer = 0; - control -> ShmemClientSize = 0; - - return 1; -} - -// -// Adjust the pack method according to the -// type of the session. -// - -int SetPack() -{ - #ifdef TEST - *logofs << "Loop: Setting pack with initial method " - << packMethod << " and quality " << packQuality - << ".\n" << logofs_flush; - #endif - - // - // Check if this is a proxy session and, in - // this case, set the pack method to none. - // Packed images are not supported by plain - // X applications. - // - - if (control -> SessionMode == session_proxy) - { - #ifdef TEST - *logofs << "Loop: WARNING! Disabling pack with proxy session.\n" - << logofs_flush; - #endif - - packMethod = PACK_NONE; - } - - // - // Adjust the internal settings according - // to the newly selected pack method. - // - - ParsePackMethod(packMethod, packQuality); - - // - // Don't load messages from persistent - // cache if packed images are disabled. - // - - if (control -> PackMethod == PACK_NONE) - { - control -> PersistentCacheLoadPacked = 0; - - #ifdef TEST - *logofs << "Loop: Not loading packed images " - << "from persistent cache.\n" - << logofs_flush; - #endif - } - - return 1; -} - -// -// Set the disk-based image cache parameters -// according to the user's wishes. -// - -int SetImages() -{ - // - // Be sure we disable the image cache if we - // are connecting to plain X clients. - // - - if (control -> SessionMode == session_proxy) - { - #ifdef TEST - *logofs << "Loop: Disabling image cache with " - << "session '" << DumpSession(control -> - SessionMode) << "'.\n" << logofs_flush; - #endif - - sprintf(imagesSizeName, "0"); - - control -> ImageCacheEnableLoad = 0; - control -> ImageCacheEnableSave = 0; - - return 1; - } - - int size = control -> ImageCacheDiskLimit; - - if (size / 1024 > 0) - { - sprintf(imagesSizeName, "%dk", size / 1024); - } - else - { - sprintf(imagesSizeName, "%d", size); - } - - if (size > 0) - { - control -> ImageCacheEnableLoad = 1; - control -> ImageCacheEnableSave = 1; - - if (control -> ProxyMode == proxy_server) - { - if ((control -> ImageCachePath = GetImagesPath()) == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error getting or creating image cache path.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error getting or creating image cache path.\n"; - - HandleCleanup(); - } - - #ifdef TEST - *logofs << "Loop: Path of image cache files is '" << control -> ImageCachePath - << "'.\n" << logofs_flush; - #endif - } - } - else - { - #ifdef TEST - *logofs << "Loop: Disabling the persistent image cache.\n" - << logofs_flush; - #endif - - control -> ImageCacheEnableLoad = 0; - control -> ImageCacheEnableSave = 0; - } - - return 1; -} - -int SetVersion() -{ - // - // Normalize the different proxy versions. - // - - int local = (control -> LocalVersionMajor << 24) | - (control -> LocalVersionMinor << 16) | - control -> LocalVersionPatch; - - int remote = (control -> RemoteVersionMajor << 24) | - (control -> RemoteVersionMinor << 16) | - control -> RemoteVersionPatch; - - int major = -1; - int minor = -1; - int patch = -1; - - if (control -> RemoteVersionMajor <= 1) - { - // - // The remote proxy uses a different - // logic to determine the version so - // we default to the compatibility - // version. - // - - major = control -> CompatVersionMajor; - minor = control -> CompatVersionMinor; - patch = control -> CompatVersionPatch; - - #ifdef TEST - *logofs << "Loop: Using compatibility version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - } - else if (control -> LocalVersionMajor > - control -> RemoteVersionMajor) - { - // - // We use a more recent version. Let's - // negotiate the version based on the - // version supported by the remote. - // - - major = control -> RemoteVersionMajor; - minor = control -> RemoteVersionMinor; - patch = control -> RemoteVersionPatch; - - #ifdef TEST - *logofs << "Loop: Using remote version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - } - else - { - // - // We support a major version that is - // equal or older than the remote. We - // assume the smaller version between - // the two, including the minor and - // the patch numbers. - // - - if (local > remote) - { - major = control -> RemoteVersionMajor; - minor = control -> RemoteVersionMinor; - patch = control -> RemoteVersionPatch; - - #ifdef TEST - *logofs << "Loop: Using remote version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - } - else - { - major = control -> LocalVersionMajor; - minor = control -> LocalVersionMinor; - patch = control -> LocalVersionPatch; - - #ifdef TEST - *logofs << "Loop: Using local version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - } - } - - // - // Handle versions from 3.5.0. The protocol - // step 10 is the minimum supported version. - // - - int step = 0; - - if (major == 3) - { - if (minor >= 5) - { - step = 10; - } - } - else if (major > 3) - { - step = 10; - } - - if (step == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unable to set the protocol step value from " - << "the negotiated protocol version " << major << "." << minor - << "." << patch << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unable to set the protocol step value from " - << "the negotiated protocol version " << major << "." << minor - << "." << patch << ".\n"; - - #ifdef PANIC - *logofs << "Loop: PANIC! Incompatible remote version " - << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor - << "." << control -> RemoteVersionPatch << " with local version " - << control -> LocalVersionMajor << "." << control -> LocalVersionMinor - << "." << control -> LocalVersionPatch << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Incompatible remote version " - << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor - << "." << control -> RemoteVersionPatch << " with local version " - << control -> LocalVersionMajor << "." << control -> LocalVersionMinor - << "." << control -> LocalVersionPatch << ".\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Loop: Using NX protocol step " - << step << ".\n" << logofs_flush; - #endif - - control -> setProtoStep(step); - - // - // Ignore the differences in patch version - // and print a warning if the local version - // is different or obsolete compared to - // the remote. - // - - local &= 0xffff0000; - remote &= 0xffff0000; - - if (local != remote) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Connected to remote version " - << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor - << "." << control -> RemoteVersionPatch << " with local version " - << control -> LocalVersionMajor << "." << control -> LocalVersionMinor - << "." << control -> LocalVersionPatch << ".\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Connected to remote version " - << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor - << "." << control -> RemoteVersionPatch << " with local version " - << control -> LocalVersionMajor << "." << control -> LocalVersionMinor - << "." << control -> LocalVersionPatch << ".\n" << logofs_flush; - } - - if (local < remote) - { - cerr << "Warning" << ": Consider checking https://github.com/ArcticaProject/nx-libs/releases for updates.\n"; - } - - // - // Now that we are aware of the remote - // version, let's adjust the options to - // be compatible with the remote proxy. - // - - if (control -> ProxyMode == proxy_client) - { - // - // Since ProtoStep8 (#issue 108) - // - // Now it's assumed that the remote is - // able to handle the selected pack - // method - // - - #ifdef TEST - *logofs << __FILE__ << " : " << __LINE__ << " - " - << "step = " << control -> getProtoStep() - << " packMethod = " << packMethod - << " packQuality = " << packQuality - << ".\n" << logofs_flush; - #endif - - // - // Update the pack method name. - // - - ParsePackMethod(packMethod, packQuality); - } - - // - // At the moment the image cache is not used by the - // agent. Proxy versions older than 3.0.0 assumed - // that it was enabled and sent specific bits as part - // of the encoding. Conversely, it is advisable to - // disable the cache right now. By not enabling the - // the image cache, the house-keeping process will - // only take care of cleaning up the "cache-" direc- - // tories. - // - - // - // Considering that compatibility with older versions - // has been set to cover as far as 3.5.0, the cache can - // be disabled at this point without any concern - // - - // Since ProtoStep8 (#issue 108) - #ifdef TEST - *logofs << "Loop: Disabling image cache with protocol " - << "step '" << control -> getProtoStep() - << "'.\n" << logofs_flush; - #endif - - sprintf(imagesSizeName, "0"); - - control -> ImageCacheEnableLoad = 0; - control -> ImageCacheEnableSave = 0; - - return 1; -} - -// -// Identify the requested link settings -// and update the control parameters -// accordingly. -// - -int SetLink() -{ - #ifdef TEST - *logofs << "Loop: Setting link with initial value " - << linkSpeedName << ".\n" << logofs_flush; - #endif - - if (*linkSpeedName == '\0') - { - strcpy(linkSpeedName, "lan"); - } - - #ifdef TEST - *logofs << "Loop: Link speed is " << linkSpeedName - << ".\n" << logofs_flush; - #endif - - if (strcasecmp(linkSpeedName, "modem") == 0) - { - SetLinkModem(); - } - else if (strcasecmp(linkSpeedName, "isdn") == 0) - { - SetLinkIsdn(); - } - else if (strcasecmp(linkSpeedName, "adsl") == 0) - { - SetLinkAdsl(); - } - else if (strcasecmp(linkSpeedName, "wan") == 0) - { - SetLinkWan(); - } - else if (strcasecmp(linkSpeedName, "lan") == 0) - { - SetLinkLan(); - } - else - { - return -1; - } - - // - // Set TCP_NODELAY according to the user's - // wishes. - // - - if (useNoDelay != -1) - { - control -> OptionProxyClientNoDelay = useNoDelay; - control -> OptionProxyServerNoDelay = useNoDelay; - } - - // - // Select the image compression method. - // - - if (packMethod == -1) - { - packMethod = control -> PackMethod; - } - - if (packQuality == -1) - { - packQuality = control -> PackQuality; - } - - if (ParsePackMethod(packMethod, packQuality) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unrecognized pack method id " - << packMethod << " with quality " << packQuality - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unrecognized pack method id " - << packMethod << " with quality " << packQuality - << ".\n"; - - HandleCleanup(); - } - - // - // Check if the user disabled the ability - // to generate simple replies at the client - // side. - // - - if (control -> SessionMode == session_proxy) - { - if (useTaint != -1) - { - control -> TaintReplies = (useTaint == 1); - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Forcing taint of replies " - << "with a proxy session.\n" - << logofs_flush; - #endif - - control -> TaintReplies = 1; - } - } - else - { - // - // There is no need to taint the - // replies if we have an agent. - // - - control -> TaintReplies = 0; - } - - // - // Be sure that the requests needing a reply - // are flushed immediately. Normal X clients - // use so many replies to make the queuing - // completely useless. - // - - if (control -> SessionMode == session_proxy) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Forcing flush on priority " - << "with a proxy session.\n" - << logofs_flush; - #endif - - control -> FlushPriority = 1; - } - - return 1; -} - -// -// Parameters for MODEM 28.8/33.6/56 Kbps. -// - -int SetLinkModem() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for MODEM.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_MODEM; - - control -> TokenSize = 256; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 50; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 3; - - return 1; -} - -// -// Parameters for ISDN 64/128 Kbps. -// - -int SetLinkIsdn() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for ISDN.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_ISDN; - - control -> TokenSize = 384; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 20; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 5; - - return 1; -} - -// -// Parameters for ADSL 256 Kbps. -// - -int SetLinkAdsl() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for ADSL.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_ADSL; - - control -> TokenSize = 1536; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 10; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 7; - - return 1; -} - -// -// Parameters for XDSL/FDDI/ATM 1/2/34 Mbps WAN. -// - -int SetLinkWan() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for WAN.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_WAN; - - control -> TokenSize = 1536; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 5; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 9; - - return 1; -} - -// -// Parameters for LAN 10/100 Mbps. -// - -int SetLinkLan() -{ - #ifdef TEST - *logofs << "Loop: Setting parameters for LAN.\n" - << logofs_flush; - #endif - - control -> LinkMode = LINK_TYPE_LAN; - - control -> TokenSize = 1536; - control -> TokenLimit = 24; - - control -> SplitMode = 1; - control -> SplitTotalSize = 128; - control -> SplitTotalStorageSize = 1048576; - - control -> SplitTimeout = 50; - control -> MotionTimeout = 0; - control -> IdleTimeout = 50; - - control -> PackMethod = PACK_ADAPTIVE; - control -> PackQuality = 9; - - return 1; -} - -// -// Identify the requested link type and set -// the control parameters accordingly. -// - -int SetCompression() -{ - if (strcasecmp(linkSpeedName, "modem") == 0) - { - SetCompressionModem(); - } - else if (strcasecmp(linkSpeedName, "isdn") == 0) - { - SetCompressionIsdn(); - } - else if (strcasecmp(linkSpeedName, "adsl") == 0) - { - SetCompressionAdsl(); - } - else if (strcasecmp(linkSpeedName, "wan") == 0) - { - SetCompressionWan(); - } - else if (strcasecmp(linkSpeedName, "lan") == 0) - { - SetCompressionLan(); - } - else - { - return -1; - } - - if (control -> LocalDeltaCompression < 0) - { - control -> LocalDeltaCompression = 1; - } - - // - // If we didn't set remote delta compression - // (as it should always be the case at client - // side) assume value of local side. - // - - if (control -> RemoteDeltaCompression < 0) - { - control -> RemoteDeltaCompression = - control -> LocalDeltaCompression; - } - - // - // If we didn't set remote compression levels - // assume values of local side. - // - - if (control -> RemoteStreamCompression < 0) - { - control -> RemoteStreamCompressionLevel = - control -> LocalStreamCompressionLevel; - - if (control -> RemoteStreamCompressionLevel > 0) - { - control -> RemoteStreamCompression = 1; - } - else - { - control -> RemoteStreamCompression = 0; - } - } - - if (control -> RemoteDataCompression < 0) - { - control -> RemoteDataCompressionLevel = - control -> LocalDataCompressionLevel; - - if (control -> RemoteDataCompressionLevel > 0) - { - control -> RemoteDataCompression = 1; - } - else - { - control -> RemoteDataCompression = 0; - } - } - - return 1; -} - -// -// Compression for MODEM. -// - -int SetCompressionModem() -{ - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 1; - control -> LocalDataCompressionLevel = 1; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 32; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 1; - control -> LocalStreamCompressionLevel = 9; - } - - return 1; -} - -// -// Compression for ISDN. -// - -int SetCompressionIsdn() -{ - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 1; - control -> LocalDataCompressionLevel = 1; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 32; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 1; - control -> LocalStreamCompressionLevel = 6; - } - - return 1; -} - -// -// Compression for ADSL. -// - -int SetCompressionAdsl() -{ - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 1; - control -> LocalDataCompressionLevel = 1; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 32; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 1; - control -> LocalStreamCompressionLevel = 4; - } - - return 1; -} - -// -// Compression for WAN. -// - -int SetCompressionWan() -{ - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 1; - control -> LocalDataCompressionLevel = 1; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 32; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 1; - control -> LocalStreamCompressionLevel = 1; - } - - return 1; -} - -// -// Compression for LAN. -// - -int SetCompressionLan() -{ - // - // Disable delta compression if not - // explicitly enabled. - // - - if (control -> LocalDeltaCompression < 0) - { - control -> LocalDeltaCompression = 0; - } - - if (control -> LocalDataCompression < 0) - { - control -> LocalDataCompression = 0; - control -> LocalDataCompressionLevel = 0; - } - - if (control -> LocalDataCompressionThreshold < 0) - { - control -> LocalDataCompressionThreshold = 0; - } - - if (control -> LocalStreamCompression < 0) - { - control -> LocalStreamCompression = 0; - control -> LocalStreamCompressionLevel = 0; - } - - return 1; -} - -int SetLimits() -{ - // - // Check if the user requested strict - // control flow parameters. - // - - if (useStrict == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: LIMIT! Decreasing the token limit " - << "to " << control -> TokenLimit / 2 - << " with option 'strict'.\n" - << logofs_flush; - #endif - - control -> TokenLimit /= 2; - } - - #ifdef STRICT - - control -> TokenLimit = 1; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: WARNING! LIMIT! Setting the token limit " - << "to " << control -> TokenLimit - << " to simulate the proxy congestion.\n" - << logofs_flush; - #endif - - #endif - - // - // Reduce the size of the log file. - // - - #ifdef QUOTA - - control -> FileSizeLimit = 8388608; - - #endif - - // - // Check the bitrate limits. - // - - if (control -> LocalBitrateLimit == -1) - { - if (control -> ProxyMode == proxy_client) - { - control -> LocalBitrateLimit = - control -> ClientBitrateLimit; - } - else - { - control -> LocalBitrateLimit = - control -> ServerBitrateLimit; - } - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: LIMIT! Setting client bitrate limit " - << "to " << control -> ClientBitrateLimit - << " server bitrate limit to " << control -> - ServerBitrateLimit << " with local limit " - << control -> LocalBitrateLimit << ".\n" - << logofs_flush; - #endif - - return 1; -} - -// -// These functions are used to parse literal -// values provided by the user and set the -// control parameters accordingly. -// - -int ParseCacheOption(const char *opt) -{ - int size = ParseArg("", "cache", opt); - - if (size < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value '" - << opt << "' for option 'cache'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value '" - << opt << "' for option 'cache'.\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Loop: Setting size of cache to " - << size << " bytes.\n" << logofs_flush; - #endif - - control -> ClientTotalStorageSize = size; - control -> ServerTotalStorageSize = size; - - strcpy(cacheSizeName, opt); - - if (size == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Disabling NX delta compression.\n" - << logofs_flush; - #endif - - control -> LocalDeltaCompression = 0; - - #ifdef WARNING - *logofs << "Loop: WARNING! Disabling use of NX persistent cache.\n" - << logofs_flush; - #endif - - control -> PersistentCacheEnableLoad = 0; - control -> PersistentCacheEnableSave = 0; - } - - return 1; -} - -int ParseImagesOption(const char *opt) -{ - int size = ParseArg("", "images", opt); - - if (size < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value '" - << opt << "' for option 'images'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value '" - << opt << "' for option 'images'.\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Loop: Setting size of images cache to " - << size << " bytes.\n" << logofs_flush; - #endif - - control -> ImageCacheDiskLimit = size; - - strcpy(imagesSizeName, opt); - - return 1; -} - -int ParseShmemOption(const char *opt) -{ - int size = ParseArg("", "shseg", opt); - - if (size < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value '" - << opt << "' for option 'shseg'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value '" - << opt << "' for option 'shseg'.\n"; - - return -1; - } - - control -> ShmemClientSize = size; - control -> ShmemServerSize = size; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Set shared memory size to " - << control -> ShmemServerSize << " bytes.\n" - << logofs_flush; - #endif - - strcpy(shsegSizeName, opt); - - return 1; -} - -int ParseBitrateOption(const char *opt) -{ - int bitrate = ParseArg("", "limit", opt); - - if (bitrate < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid value '" - << opt << "' for option 'limit'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Invalid value '" - << opt << "' for option 'limit'.\n"; - - return -1; - } - - strcpy(bitrateLimitName, opt); - - if (bitrate == 0) - { - #ifdef TEST - *logofs << "Loop: Disabling bitrate limit on proxy link.\n" - << logofs_flush; - #endif - - control -> LocalBitrateLimit = 0; - } - else - { - #ifdef TEST - *logofs << "Loop: Setting bitrate to " << bitrate - << " bits per second.\n" << logofs_flush; - #endif - - // - // Internal representation is in bytes - // per second. - // - - control -> LocalBitrateLimit = bitrate >> 3; - } - - return 1; -} - -int ParseHostOption(const char *opt, char *host, long &port) -{ - #ifdef TEST - *logofs << "Loop: Trying to parse options string '" << opt - << "' as a remote NX host.\n" << logofs_flush; - #endif - - if (opt == NULL || *opt == '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! No host parameter provided.\n" - << logofs_flush; - #endif - - return 0; - } - else if (strlen(opt) >= DEFAULT_STRING_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Host parameter exceeds length of " - << DEFAULT_STRING_LENGTH << " characters.\n" - << logofs_flush; - #endif - - return 0; - } - - // - // Look for a host name followed - // by a colon followed by port. - // - - int newPort = port; - - const char *separator = strrchr(opt, ':'); - - if (separator != NULL) - { - const char *check = separator + 1; - - while (*check != '\0' && *check != ',' && - *check != '=' && isdigit(*check) != 0) - { - check++; - } - - newPort = atoi(separator + 1); - - if (newPort < 0 || *check != '\0') - { - #ifdef TEST - *logofs << "Loop: Can't identify remote NX port in string '" - << separator << "'.\n" << logofs_flush; - #endif - - return 0; - } - } - else if (newPort < 0) - { - // - // Complain if port was not passed - // by other means. - // - - #ifdef TEST - *logofs << "Loop: Can't identify remote NX port in string '" - << opt << "'.\n" << logofs_flush; - #endif - - return 0; - } - else - { - separator = opt + strlen(opt); - } - - char newHost[DEFAULT_STRING_LENGTH] = { 0 }; - - strncpy(newHost, opt, strlen(opt) - strlen(separator)); - - *(newHost + strlen(opt) - strlen(separator)) = '\0'; - - const char *check = newHost; - - while (*check != '\0' && *check != ',' && - *check != '=') - { - check++; - } - - if (*check != '\0') - { - #ifdef TEST - *logofs << "Loop: Can't identify remote NX host in string '" - << newHost << "'.\n" << logofs_flush; - #endif - - return 0; - } - else if (*acceptHost != '\0') - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't manage to connect and accept connections " - << "at the same time.\n" << logofs_flush; - - *logofs << "Loop: PANIC! Refusing remote NX host with string '" - << opt << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't manage to connect and accept connections " - << "at the same time.\n"; - - cerr << "Error" << ": Refusing remote NX host with string '" - << opt << "'.\n"; - - return -1; - } - - if (*host != '\0' && strcmp(host, newHost) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding remote NX host '" - << host << "' with new value '" << newHost - << "'.\n" << logofs_flush; - #endif - } - - strcpy(host, newHost); - - if (port != -1 && port != newPort) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Overriding remote NX port '" - << port << "' with new value '" << newPort - << "'.\n" << logofs_flush; - #endif - } - - #ifdef TEST - *logofs << "Loop: Parsed options string '" << opt - << "' with host '" << newHost << "' and port '" - << newPort << "'.\n" << logofs_flush; - #endif - - port = newPort; - - return 1; -} - -int ParseFontPath(char *path) -{ - char oldPath[DEFAULT_STRING_LENGTH]; - - strcpy(oldPath, path); - - if (path == NULL || *path == '\0' || strcmp(path, "0") == 0) - { - return 0; - } - - #ifdef TEST - *logofs << "Loop: Parsing font server option '" << path - << "'.\n" << logofs_flush; - #endif - - // - // Convert the value to our default port. - // - - if (strcmp(fontPort, "1") == 0) - { - if (control -> ProxyMode == proxy_server) - { - snprintf(fontPort, DEFAULT_STRING_LENGTH - 1, "%d", - DEFAULT_NX_FONT_PORT_OFFSET + proxyPort); - } - else - { - // - // Let the client use the well-known - // "unix/:7100" font path. - // - - snprintf(fontPort, DEFAULT_STRING_LENGTH - 1, "unix/:7100"); - } - } - - // - // Check if a simple numaric value was given. - // - - if (atoi(path) > 0) - { - #ifdef TEST - *logofs << "Loop: Assuming numeric TCP port '" << atoi(path) - << "' for font server.\n" << logofs_flush; - #endif - - return 1; - } - - // - // Let's assume that a port specification "unix/:7100" - // corresponds to "$TEMP/.font-unix/fs7100" and a port - // "unix/:-1" corresponds to "$TEMP/.font-unix/fs-1". - // - - if (strncmp("unix/:", path, 6) == 0) - { - snprintf(path, DEFAULT_STRING_LENGTH - 1, "%s/.font-unix/fs%s", - control -> TempPath, oldPath + 6); - - *(path + DEFAULT_STRING_LENGTH - 1) = '\0'; - - #ifdef TEST - *logofs << "Loop: Assuming Unix socket '" << path - << "' for font server.\n" << logofs_flush; - #endif - } - else if (strncmp("tcp/:", path, 5) == 0) - { - snprintf(path, DEFAULT_STRING_LENGTH - 1, "%d", atoi(oldPath + 5)); - - *(path + DEFAULT_STRING_LENGTH - 1) = '\0'; - - if (atoi(path) <= 0) - { - goto ParseFontPathError; - } - - #ifdef TEST - *logofs << "Loop: Assuming TCP port '" << atoi(path) - << "' for font server.\n" << logofs_flush; - #endif - } - else - { - // - // Accept an absolute file path as - // a valid Unix socket. - // - - if (*path != '/') - { - goto ParseFontPathError; - } - - #ifdef TEST - *logofs << "Loop: Assuming Unix socket '" << path - << "' for font server.\n" << logofs_flush; - #endif - } - - return 1; - -ParseFontPathError: - - #ifdef TEST - *logofs << "Loop: Unable to determine the font server " - << "port in string '" << path << "'.\n" - << logofs_flush; - #endif - - return -1; -} - -int OpenLogFile(char *name, ostream *&stream) -{ - if (name == NULL || *name == '\0') - { - #ifdef TEST - *logofs << "Loop: WARNING! No name provided for output. Using standard error.\n" - << logofs_flush; - #endif - - if (stream == NULL) - { - stream = &cerr; - } - - return 1; - } - - if (stream == NULL || stream == &cerr) - { - if (*name != '/' && *name != '.') - { - char *filePath = GetSessionPath(); - - if (filePath == NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Cannot determine directory of NX session file.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Cannot determine directory of NX session file.\n"; - - return -1; - } - - if (strlen(filePath) + strlen("/") + - strlen(name) + 1 > DEFAULT_STRING_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Full name of NX file '" << name - << " would exceed length of " << DEFAULT_STRING_LENGTH - << " characters.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Full name of NX file '" << name - << " would exceed length of " << DEFAULT_STRING_LENGTH - << " characters.\n"; - - return -1; - } - - char *file = new char[strlen(filePath) + strlen("/") + - strlen(name) + 1]; - - // - // Transform name in a fully qualified name. - // - - strcpy(file, filePath); - strcat(file, "/"); - strcat(file, name); - - strcpy(name, file); - - delete [] filePath; - delete [] file; - } - - mode_t fileMode = umask(0077); - - for (;;) - { - if ((stream = new ofstream(name, ios::app)) != NULL) - { - break; - } - - usleep(200000); - } - - umask(fileMode); - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Bad stream provided for output.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Bad stream provided for output.\n"; - - return -1; - } - - return 1; -} - -int ReopenLogFile(char *name, ostream *&stream, int limit) -{ - if (*name != '\0' && limit >= 0) - { - struct stat fileStat; - - if (limit > 0) - { - // - // This is used for the log file, if the - // size exceeds the limit. - // - - if (stat(name, &fileStat) != 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Can't get stats of file '" - << name << "'. Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - return 0; - } - else if (fileStat.st_size < (long) limit) - { - return 0; - } - } - - #ifdef TEST - *logofs << "Loop: Deleting file '" << name - << "' with size " << fileStat.st_size - << ".\n" << logofs_flush; - #endif - - // - // Create a new stream over the previous - // file. Trying to delete the file fails - // to work on recent Cygwin installs. - // - - *stream << flush; - - delete stream; - - mode_t fileMode = umask(0077); - - for (;;) - { - if ((stream = new ofstream(name, ios::out)) != NULL) - { - break; - } - - usleep(200000); - } - - umask(fileMode); - - #ifdef TEST - *logofs << "Loop: Reopened file '" << name - << "'.\n" << logofs_flush; - #endif - } - - return 1; -} - -void PrintProcessInfo() -{ - if (agent == NULL) - { - - cerr << endl; - - PrintVersionInfo(); - - cerr << endl; - - cerr << GetCopyrightInfo() - << endl - << GetOtherCopyrightInfo() - << endl - << "See https://github.com/ArcticaProject/nx-libs for more information." << endl << endl; - } - - // - // People get confused by the fact that client - // mode is running on NX server and viceversa. - // Let's adopt an user-friendly naming conven- - // tion here. - // - - cerr << "Info: Proxy running in " - << (control -> ProxyMode == proxy_client ? "client" : "server") - << " mode with pid '" << getpid() << "'.\n"; - - if (agent == NULL) - { - cerr << "Session" << ": Starting session at '" - << strTimestamp() << "'.\n"; - } - - #ifdef TEST - - if (*errorsFileName != '\0') - { - cerr << "Info" << ": Using errors file '" << errorsFileName << "'.\n"; - } - - if (*statsFileName != '\0') - { - cerr << "Info" << ": Using stats file '" << statsFileName << "'.\n"; - } - - #endif -} - -void PrintConnectionInfo() -{ - cerr << "Info" << ": Using " - << linkSpeedName << " link parameters " - << control -> TokenSize - << "/" << control -> TokenLimit - << "/" << control -> FlushPolicy + 1 - << "/" << control -> FlushPriority - << ".\n"; - - if (control -> ProxyMode == proxy_client) - { - cerr << "Info" << ": Using agent parameters " - << control -> PingTimeout - << "/" << control -> MotionTimeout - << "/" << control -> IdleTimeout - << "/" << control -> TaintReplies - << "/" << control -> HideRender - << ".\n"; - } - - if (control -> LocalDeltaCompression == 1) - { - cerr << "Info" << ": Using cache parameters " - << control -> MinimumMessageSize - << "/" << control -> MaximumMessageSize / 1024 << "KB" - << "/" << control -> ClientTotalStorageSize / 1024 << "KB" - << "/" << control -> ServerTotalStorageSize / 1024 << "KB" - << ".\n"; - } - - if (control -> ImageCacheEnableLoad == 1 || - control -> ImageCacheEnableSave == 1) - { - cerr << "Info" << ": Using image streaming parameters " - << control -> SplitTimeout - << "/" << control -> SplitTotalSize - << "/" << control -> SplitTotalStorageSize / 1024 << "KB" - << "/" << control -> SplitDataThreshold - << "/" << control -> SplitDataPacketLimit - << ".\n"; - - cerr << "Info" << ": Using image cache parameters " - << control -> ImageCacheEnableLoad - << "/" << control -> ImageCacheEnableSave - << "/" << control -> ImageCacheDiskLimit / 1024 << "KB" - << ".\n"; - } - - cerr << "Info" << ": Using pack method '" - << packMethodName << "' with session '" - << sessionType << "'.\n"; - - if (*productName != '\0') - { - cerr << "Info" << ": Using product '" << productName - << "'.\n" << logofs_flush; - } - - if (control -> LocalDeltaCompression == 0) - { - cerr << "Info" << ": Not using NX delta compression.\n"; - } - - if (control -> LocalDataCompression == 1 || - control -> RemoteDataCompression == 1) - { - cerr << "Info" << ": Using ZLIB data compression " - << control -> LocalDataCompressionLevel - << "/" << control -> RemoteDataCompressionLevel - << "/" << control -> LocalDataCompressionThreshold - << ".\n"; - } - else - { - cerr << "Info" << ": Not using ZLIB data compression.\n"; - } - - if (control -> LocalStreamCompression == 1 || - control -> RemoteStreamCompression == 1) - { - cerr << "Info" << ": Using ZLIB stream compression " - << control -> LocalStreamCompressionLevel - << "/" << control -> RemoteStreamCompressionLevel - << ".\n"; - } - else - { - cerr << "Info" << ": Not using ZLIB stream compression.\n"; - } - - if (control -> LocalBitrateLimit > 0) - { - cerr << "Info" << ": Using bandwidth limit of " - << bitrateLimitName << " bits per second.\n"; - } - - if (control -> PersistentCacheName != NULL) - { - cerr << "Info" << ": Using cache file '" - << control -> PersistentCachePath << "/" - << control -> PersistentCacheName << "'.\n"; - } - else - { - if (control -> PersistentCacheEnableLoad == 0 || - control -> LocalDeltaCompression == 0) - { - cerr << "Info" << ": Not using a persistent cache.\n"; - } - else - { - cerr << "Info" << ": No suitable cache file found.\n"; - } - } - - if (control -> ProxyMode == proxy_client && - (useUnixSocket > 0 || useTcpSocket > 0 || - useAgentSocket > 0)) - { - cerr << "Info" << ": Listening to X11 connections " - << "on display ':" << xPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server) - { - cerr << "Info" << ": Forwarding X11 connections " - << "to display '" << displayHost << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useCupsSocket > 0 && cupsPort.enabled()) - { - cerr << "Info" << ": Listening to CUPS connections " - << "on port '" << cupsPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - cupsPort.enabled()) - { - cerr << "Info" << ": Forwarding CUPS connections " - << "to port '" << cupsPort << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useAuxSocket > 0 && auxPort.enabled()) - { - cerr << "Info" << ": Listening to auxiliary X11 connections " - << "on port '" << auxPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - auxPort.enabled()) - { - cerr << "Info" << ": Forwarding auxiliary X11 connections " - << "to display '" << displayHost << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useSmbSocket > 0 && smbPort.enabled()) - { - cerr << "Info" << ": Listening to SMB connections " - << "on port '" << smbPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - smbPort.enabled()) - { - cerr << "Info" << ": Forwarding SMB connections " - << "to port '" << smbPort << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useMediaSocket > 0 && mediaPort.enabled()) - { - cerr << "Info" << ": Listening to multimedia connections " - << "on port '" << mediaPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - mediaPort.enabled()) - { - cerr << "Info" << ": Forwarding multimedia connections " - << "to port '" << mediaPort << "'.\n"; - } - - if (control -> ProxyMode == proxy_client && - useHttpSocket > 0 && httpPort.enabled()) - { - cerr << "Info" << ": Listening to HTTP connections " - << "on port '" << httpPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_server && - httpPort.enabled()) - { - cerr << "Info" << ": Forwarding HTTP connections " - << "to port '" << httpPort << "'.\n"; - } - - if (control -> ProxyMode == proxy_server && - useFontSocket > 0 && *fontPort != '\0') - { - cerr << "Info" << ": Listening to font server connections " - << "on port '" << fontPort << "'.\n"; - } - else if (control -> ProxyMode == proxy_client && - *fontPort != '\0') - { - cerr << "Info" << ": Forwarding font server connections " - << "to port '" << fontPort << "'.\n"; - } - - if (useSlaveSocket > 0 && slavePort.enabled()) - { - cerr << "Info" << ": Listening to slave connections " - << "on port '" << slavePort << "'.\n"; - } -} - -void PrintVersionInfo() -{ - cerr << "NXPROXY - " << "Version " - << control -> LocalVersionMajor << "." - << control -> LocalVersionMinor << "." - << control -> LocalVersionPatch << "." - << control -> LocalVersionMaintenancePatch; - - cerr << endl; -} - -void PrintCopyrightInfo() -{ - cerr << endl; - - PrintVersionInfo(); - - cerr << endl; - - cerr << GetCopyrightInfo(); - - // - // Print third party's copyright info. - // - - cerr << endl; - - cerr << GetOtherCopyrightInfo(); - - cerr << endl; -} - -void PrintOptionIgnored(const char *type, const char *name, const char *value) -{ - if (control -> ProxyMode == proxy_server) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring " << type - << " option '" << name << "' with value '" - << value << "' at " << "NX client side.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring " << type - << " option '" << name << "' with value '" - << value << "' at " << "NX client side.\n"; - } - else - { - #ifdef WARNING - *logofs << "Loop: WARNING! Ignoring " << type - << " option '" << name << "' with value '" - << value << "' at " << "NX server side.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Ignoring " << type - << " option '" << name << "' with value '" - << value << "' at " << "NX server side.\n"; - } -} - -const char *GetOptions(const char *options) -{ - if (options != NULL) - { - if (strncasecmp(options, "nx/nx,", 6) != 0 && - strncasecmp(options, "nx,", 3) != 0 && - strncasecmp(options, "nx:", 3) != 0) - { - #ifdef TEST - *logofs << "Loop: PANIC! Display options string '" << options - << "' must start with 'nx' or 'nx/nx' prefix.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Display options string '" << options - << "' must start with 'nx' or 'nx/nx' prefix.\n"; - - HandleCleanup(); - } - } - else - { - options = getenv("DISPLAY"); - } - - return options; -} - -const char *GetArg(int &argi, int argc, const char **argv) -{ - // - // Skip "-" and flag character. - // - - const char *arg = argv[argi] + 2; - - if (*arg == 0) - { - if (argi + 1 == argc) - { - return NULL; - } - else - { - argi++; - - return (*argv[argi] == '-' ? NULL : argv[argi]); - } - } - else - { - return (*arg == '-' ? NULL : arg); - } -} - -int CheckArg(const char *type, const char *name, const char *value) -{ - #ifdef TEST - *logofs << "Loop: Parsing " << type << " option '" << name - << "' with value '" << (value ? value : "(null)") - << "'.\n" << logofs_flush; - #endif - - if (value == NULL || strstr(value, "=") != NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error in " << type << " option '" - << name << "'. No value found.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error in " << type << " option '" - << name << "'. No value found.\n"; - - return -1; - } - else if (strstr(name, ",") != NULL) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Parse error at " << type << " option '" - << name << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Parse error at " << type << " option '" - << name << "'.\n"; - - return -1; - } - else if (strlen(value) >= DEFAULT_STRING_LENGTH) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Value '" << value << "' of " - << type << " option '" << name << "' exceeds length of " - << DEFAULT_STRING_LENGTH << " characters.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Value '" << value << "' of " - << type << " option '" << name << "' exceeds length of " - << DEFAULT_STRING_LENGTH << " characters.\n"; - - return -1; - } - - return 1; -} - -int ParseArg(const char *type, const char *name, const char *value) -{ - if (strcasecmp(value, "0") == 0) - { - return 0; - } - - // - // Find the base factor. - // - - double base; - - const char *id = value + strlen(value) - 1; - - if (strcasecmp(id, "g") == 0) - { - base = 1024 * 1024 * 1024; - } - else if (strcasecmp(id, "m") == 0) - { - base = 1024 * 1024; - } - else if (strcasecmp(id, "k") == 0) - { - base = 1024; - } - else if (strcasecmp(id, "b") == 0 || isdigit(*id) == 1) - { - base = 1; - } - else - { - return -1; - } - - char *string = new char[strlen(value)]; - - strncpy(string, value, strlen(value) - 1); - - *(string + (strlen(value) - 1)) = '\0'; - - #ifdef TEST - - *logofs << "Loop: Parsing integer option '" << name - << "' from string '" << string << "' with base set to "; - - switch (tolower(*id)) - { - case 'k': - case 'm': - case 'g': - { - *logofs << (char) toupper(*id); - } - break; - } - - *logofs << ".\n" << logofs_flush; - - #endif - - double result = atof(string) * base; - - if (result < 0 || result > (((unsigned) -1) >> 1)) - { - delete [] string; - - return -1; - } - - delete [] string; - - #ifdef TEST - *logofs << "Loop: Integer option parsed to '" - << (int) result << "'.\n" << logofs_flush; - #endif - - return (int) result; -} - -void SetAndValidateChannelEndPointArg(const char *type, const char *name, const char *value, - ChannelEndPoint &endPoint) { - endPoint.setSpec(value); - if (!endPoint.validateSpec()) { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid " << type - << " option '" << name << "' with value '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid " << type - << " option '" << name << "' with value '" - << value << "'.\n"; - - HandleCleanup(); - } -} - - -int ValidateArg(const char *type, const char *name, const char *value) -{ - int number = atoi(value); - - if (number < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Invalid " << type - << " option '" << name << "' with value '" - << value << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid " << type - << " option '" << name << "' with value '" - << value << "'.\n"; - - HandleCleanup(); - } - - return number; -} - -int LowercaseArg(const char *type, const char *name, char *value) -{ - char *next = value; - - while (*next != '\0') - { - *next = tolower(*next); - - next++; - } - - return 1; -} - -int CheckSignal(int signal) -{ - // - // Return 1 if the signal needs to be handled - // by the proxy, 2 if the signal just needs to - // be blocked to avoid interrupting a system - // call. - // - - switch (signal) - { - case SIGCHLD: - case SIGUSR1: - case SIGUSR2: - case SIGHUP: - case SIGINT: - case SIGTERM: - case SIGPIPE: - case SIGALRM: - { - return 1; - } - case SIGVTALRM: - case SIGWINCH: - case SIGIO: - case SIGTSTP: - case SIGTTIN: - case SIGTTOU: - { - return 2; - } - default: - { - #ifdef __CYGWIN32__ - - // - // This signal can be raised by the Cygwin - // library. - // - - if (signal == 12) - { - return 1; - } - - #endif - - return 0; - } - } -} - -static void PrintUsageInfo(const char *option, int error) -{ - if (error == 1) - { - cerr << "Error" << ": Invalid command line option '" << option << "'.\n"; - } - - cerr << GetUsageInfo(); - - if (error == 1) - { - cerr << "Error" << ": NX transport initialization failed.\n"; - } -} - -static void handleCheckSessionInLoop() -{ - // - // Check if we completed the shutdown procedure - // and the remote confirmed the shutdown. The - // tear down should be always initiated by the - // agent, but the X server side may unilateral- - // ly shut down the link without our permission. - // - - if (proxy -> getShutdown() > 0) - { - #ifdef TEST - *logofs << "Loop: End of NX transport requested " - << "by remote.\n" << logofs_flush; - #endif - - handleTerminatingInLoop(); - - if (control -> ProxyMode == proxy_server) - { - #ifdef TEST - *logofs << "Loop: Bytes received so far are " - << (unsigned long long) statistics -> getBytesIn() - << ".\n" << logofs_flush; - #endif - - if (statistics -> getBytesIn() < 1024) - { - cerr << "Info" << ": Your session was closed before reaching " - << "a usable state.\n"; - cerr << "Info" << ": This can be due to the local X server " - << "refusing access to the client.\n"; - cerr << "Info" << ": Please check authorization provided " - << "by the remote X application.\n"; - } - } - - #ifdef TEST - *logofs << "Loop: Shutting down the NX transport.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - else if (proxy -> handlePing() < 0) - { - #ifdef TEST - *logofs << "Loop: Failure handling the ping for " - << "proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - HandleShutdown(); - } - - // - // Check if the watchdog has exited and we didn't - // get the SIGCHLD. This can happen if the parent - // has overridden our signal handlers. - // - - if (IsRunning(lastWatchdog) && CheckProcess(lastWatchdog, "watchdog") == 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Watchdog is gone unnoticed. " - << "Setting the last signal to SIGTERM.\n" - << logofs_flush; - #endif - - lastSignal = SIGTERM; - - #ifdef WARNING - *logofs << "Loop: WARNING! Resetting pid of last " - << "watchdog process.\n" << logofs_flush; - #endif - - SetNotRunning(lastWatchdog); - } - - // - // Let the client proxy find out if the agent's - // channel is gone. This is the normal shutdown - // procedure in the case of an internal connect- - // ion to the agent. - // - - int cleanup = 0; - - if (control -> ProxyMode == proxy_client && - agent != NULL && proxy -> getType(agentFD[1]) == - channel_none && lastKill == 0 && lastDestroy == 1) - { - #ifdef TEST - *logofs << "Loop: End of NX transport requested " - << "by agent.\n" << logofs_flush; - #endif - - #ifdef TEST - *logofs << "Loop: Bytes sent so far are " - << (unsigned long long) statistics -> getBytesOut() - << ".\n" << logofs_flush; - #endif - - if (statistics -> getBytesOut() < 1024) - { - cerr << "Info" << ": Your session has died before reaching " - << "an usable state.\n"; - cerr << "Info" << ": This can be due to the remote X server " - << "refusing access to the client.\n"; - cerr << "Info" << ": Please check the authorization provided " - << "by your X application.\n"; - } - - cleanup = 1; - } - - // - // Check if the user requested the end of the - // session by sending a signal to the proxy. - // All signals are handled in the main loop - // so we need to reset the value to get ready - // for the next iteration. - // - - int signal = 0; - - if (lastSignal != 0) - { - switch (lastSignal) - { - case SIGCHLD: - case SIGUSR1: - case SIGUSR2: - { - break; - } - default: - { - signal = lastSignal; - - cleanup = 1; - - break; - } - } - - lastSignal = 0; - } - - if (cleanup == 1) - { - // - // The first time termination signal is received - // disable all further connections, close down any - // X channel and wait for a second signal. - // - - if (lastKill == 0) - { - // - // Don't print a message if cleanup is - // due to normal termination of agent. - // - - if (signal != 0) - { - #ifdef TEST - *logofs << "Loop: End of NX transport requested by signal '" - << signal << "' '" << DumpSignal(signal) - << "'.\n" << logofs_flush; - #endif - - handleTerminatingInLoop(); - } - - // - // Disable any further connection. - // - - CleanupListeners(); - - // - // Close all the remaining X channels and - // let proxies save their persistent cache - // on disk. - // - - CleanupConnections(); - - // - // We'll need to wait for the X channels - // to be shut down before waiting for the - // cleanup signal. - // - - lastKill = 1; - } - else if (lastKill == 2) - { - #ifdef TEST - *logofs << "Loop: Shutting down the NX transport.\n" - << logofs_flush; - #endif - - proxy -> handleShutdown(); - - HandleCleanup(); - } - } - - if (lastKill == 1 && proxy -> getChannels(channel_x11) == 0) - { - // - // Save the message stores to the - // persistent cache. - // - - proxy -> handleSave(); - - // - // Run a watchdog process so we can finally - // give up at the time the watchdog exits. - // - - if (IsNotRunning(lastWatchdog)) - { - int timeout = control -> CleanupTimeout; - - if (timeout > 0) - { - if (proxy -> getChannels() == 0) - { - timeout = 500; - } - - #ifdef TEST - *logofs << "Loop: Starting watchdog process with timeout " - << "of " << timeout << " Ms.\n" - << logofs_flush; - #endif - } - #ifdef TEST - else - { - *logofs << "Loop: Starting watchdog process without " - << "a timeout.\n" << logofs_flush; - } - #endif - - lastWatchdog = NXTransWatchdog(timeout); - - if (IsFailed(lastWatchdog)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't start the NX watchdog " - << "process in shutdown.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't start the NX watchdog " - << "process in shutdown.\n"; - - HandleCleanup(); - } - #ifdef TEST - else - { - *logofs << "Loop: Watchdog started with pid '" - << lastWatchdog << "'.\n" << logofs_flush; - } - #endif - } - else - { - #ifdef PANIC - *logofs << "Loop: PANIC! Previous watchdog detected " - << "in shutdown with pid '" << lastWatchdog - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Previous watchdog detected " - << "in shutdown with pid '" << lastWatchdog - << "'.\n"; - - HandleCleanup(); - } - - if (control -> CleanupTimeout > 0) - { - #ifdef TEST - *logofs << "Loop: Waiting the cleanup timeout to complete.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Waiting the cleanup timeout to complete.\n"; - } - else - { - // - // The NX server will kill the watchdog - // process after having shut down the - // service channels. - // - - cerr << "Info" << ": Watchdog running with pid '" << lastWatchdog - << "'.\n"; - - #ifdef TEST - *logofs << "Loop: Waiting the watchdog process to complete.\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Waiting the watchdog process to complete.\n"; - } - - lastKill = 2; - } -} - -static void handleCheckBitrateInLoop() -{ - static long int slept = 0; - - #ifdef TEST - *logofs << "Loop: Bitrate is " << statistics -> getBitrateInShortFrame() - << " B/s and " << statistics -> getBitrateInLongFrame() - << " B/s in " << control -> ShortBitrateTimeFrame / 1000 - << "/" << control -> LongBitrateTimeFrame / 1000 - << " seconds timeframes.\n" << logofs_flush; - #endif - - // - // This can be improved. We may not jump out - // of the select often enough to guarantee - // the necessary accuracy. - // - - if (control -> LocalBitrateLimit > 0) - { - #ifdef TEST - *logofs << "Loop: Calculating bandwidth usage with limit " - << control -> LocalBitrateLimit << ".\n" - << logofs_flush; - #endif - - int reference = (statistics -> getBitrateInLongFrame() + - statistics -> getBitrateInShortFrame()) / 2; - - if (reference > control -> LocalBitrateLimit) - { - double ratio = ((double) reference) / - ((double) control -> LocalBitrateLimit); - - if (ratio > 1.2) - { - ratio = 1.2; - } - - slept += (unsigned int) (pow(50000, ratio) / 1000); - - if (slept > 2000) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Sleeping due to " - << "reference bitrate of " << reference - << " B/s.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Sleeping due to " - << "reference bitrate of " << reference - << " B/s.\n"; - - slept %= 2000; - } - - T_timestamp idleTs = getNewTimestamp(); - - usleep((unsigned int) pow(50000, ratio)); - - int diffTs = diffTimestamp(idleTs, getNewTimestamp()); - - statistics -> addIdleTime(diffTs); - - statistics -> subReadTime(diffTs); - } - } -} - -#if defined(TEST) || defined(INFO) - -static void handleCheckStateInLoop(int &setFDs) -{ - int fdLength; - int fdPending; - int fdSplits; - - for (int j = 0; j < setFDs; j++) - { - if (j != proxyFD) - { - fdPending = proxy -> getPending(j); - - if (fdPending > 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Buffer for descriptor FD#" - << j << " has pending bytes to read.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - - fdLength = proxy -> getLength(j); - - if (fdLength > 0) - { - #ifdef TEST - *logofs << "Loop: WARNING! Buffer for descriptor FD#" - << j << " has " << fdLength << " bytes to write.\n" - << logofs_flush; - #endif - } - } - } - - fdPending = proxy -> getPending(proxyFD); - - if (fdPending > 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Buffer for proxy descriptor FD#" - << proxyFD << " has pending bytes to read.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - - fdLength = proxy -> getFlushable(proxyFD); - - if (fdLength > 0) - { - if (control -> FlushPolicy == policy_immediate && - proxy -> getBlocked(proxyFD) == 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Buffer for proxy descriptor FD#" - << proxyFD << " has " << fdLength << " bytes " - << "to write with policy 'immediate'.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - else - { - #ifdef TEST - *logofs << "Loop: WARNING! Buffer for proxy descriptor FD#" - << proxyFD << " has " << fdLength << " bytes " - << "to write.\n" << logofs_flush; - #endif - } - } - - fdSplits = proxy -> getSplitSize(); - - if (fdSplits > 0) - { - #ifdef WARNING - *logofs << "Loop: WARNING! Proxy descriptor FD#" << proxyFD - << " has " << fdSplits << " splits to send.\n" - << logofs_flush; - #endif - } -} - -static void handleCheckSelectInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, T_timestamp selectTs) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Maximum descriptors is [" - << setFDs << "] at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - int i; - - if (setFDs > 0) - { - i = 0; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Selected for read are "; - #endif - - for (int j = 0; j < setFDs; j++) - { - if (FD_ISSET(j, &readSet)) - { - #if defined(TEST) || defined(INFO) - *logofs << "[" << j << "]" << logofs_flush; - #endif - - i++; - } - } - - if (i > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << ".\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "[none].\n" << logofs_flush; - #endif - } - - i = 0; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Selected for write are "; - #endif - - for (int j = 0; j < setFDs; j++) - { - if (FD_ISSET(j, &writeSet)) - { - #if defined(TEST) || defined(INFO) - *logofs << "[" << j << "]" << logofs_flush; - #endif - - i++; - } - } - - if (i > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << ".\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "[none].\n" << logofs_flush; - #endif - } - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Select timeout is " - << selectTs.tv_sec << " S and " - << (double) selectTs.tv_usec / 1000 - << " Ms.\n" << logofs_flush; - #endif -} - -static void handleCheckResultInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs, - struct timeval &startTs) -{ - int diffTs = diffTimestamp(startTs, getNewTimestamp()); - - #if defined(TEST) || defined(INFO) - - if (diffTs >= (control -> PingTimeout - - (control -> LatencyTimeout * 4))) - { - *logofs << "Loop: Select result is [" << resultFDs - << "] at " << strMsTimestamp() << " with no " - << "communication within " << diffTs - << " Ms.\n" << logofs_flush; - } - else - { - *logofs << "Loop: Select result is [" << resultFDs - << "] error is [" << errorFDs << "] at " - << strMsTimestamp() << " after " << diffTs - << " Ms.\n" << logofs_flush; - } - - #endif - - int i; - - if (resultFDs > 0) - { - i = 0; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Selected for read are "; - #endif - - for (int j = 0; j < setFDs; j++) - { - if (FD_ISSET(j, &readSet)) - { - #if defined(TEST) || defined(INFO) - *logofs << "[" << j << "]" << logofs_flush; - #endif - - i++; - } - } - - if (i > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << ".\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "[none].\n" << logofs_flush; - #endif - } - - i = 0; - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Selected for write are "; - #endif - - for (int j = 0; j < setFDs; j++) - { - if (FD_ISSET(j, &writeSet)) - { - #if defined(TEST) || defined(INFO) - *logofs << "[" << j << "]" << logofs_flush; - #endif - - i++; - } - } - - if (i > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << ".\n" << logofs_flush; - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "[none].\n" << logofs_flush; - #endif - } - } -} - -#endif - -static void handleCheckSessionInConnect() -{ - #ifdef TEST - *logofs << "Loop: Going to check session in connect.\n" - << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_client) - { - HandleAlert(FAILED_PROXY_CONNECTION_CLIENT_ALERT, 1); - } - else if (IsNotRunning(lastDialog)) - { - HandleAlert(FAILED_PROXY_CONNECTION_SERVER_ALERT, 1); - } - - handleAlertInLoop(); -} - -static void handleStatisticsInLoop() -{ - if (lastSignal == 0) - { - return; - } - - int mode = NO_STATS; - - if (control -> EnableStatistics == 1) - { - if (lastSignal == SIGUSR1) - { - // - // Print overall statistics. - // - - mode = TOTAL_STATS; - } - else if (lastSignal == SIGUSR2) - { - // - // Print partial statistics. - // - - mode = PARTIAL_STATS; - } - - if (mode == TOTAL_STATS || mode == PARTIAL_STATS) - { - #ifdef TEST - *logofs << "Loop: Going to request proxy statistics " - << "with signal '" << DumpSignal(lastSignal) - << "'.\n" << logofs_flush; - #endif - - if (proxy != NULL) - { - if (ReopenLogFile(statsFileName, statofs, 0) < 0) - { - HandleCleanup(); - } - - proxy -> handleStatistics(mode, statofs); - } - } - } -} - -static void handleNegotiationInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, T_timestamp &selectTs) -{ - int yield = 0; - - while (yield == 0) - { - #ifdef TEST - *logofs << "Loop: Going to run a new negotiation loop " - << "with stage " << control -> ProxyStage - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - switch (control -> ProxyStage) - { - case stage_undefined: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_undefined" << "'.\n" - << logofs_flush; - #endif - - control -> ProxyStage = stage_initializing; - - break; - } - case stage_initializing: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_initializing" << "'.\n" - << logofs_flush; - #endif - - InitBeforeNegotiation(); - - control -> ProxyStage = stage_connecting; - - break; - } - case stage_connecting: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_connecting" << "'.\n" - << logofs_flush; - #endif - - SetupProxyConnection(); - - control -> ProxyStage = stage_connected; - - break; - } - case stage_connected: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_connected" << "'.\n" - << logofs_flush; - #endif - - // - // Server side proxy must always be the one that - // sends its version and options first, so, in - // some way, client side can be the the one that - // has the last word on the matter. - // - - if (control -> ProxyMode == proxy_server) - { - // - // Check if we have been listening for a - // forwarder. In this case it will have to - // authenticate itself. - // - - if (WE_LISTEN_FORWARDER) - { - control -> ProxyStage = stage_waiting_forwarder_version; - - break; - } - - control -> ProxyStage = stage_sending_proxy_options; - } - else - { - // - // The X client side is the side that has to wait - // for the authorization cookie and any remote - // option. - // - - control -> ProxyStage = stage_waiting_proxy_version; - } - - break; - } - case stage_sending_proxy_options: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_sending_proxy_options" << "'.\n" - << logofs_flush; - #endif - - if (SendProxyOptions(proxyFD) < 0) - { - goto handleNegotiationInLoopError; - } - - if (control -> ProxyMode == proxy_server) - { - control -> ProxyStage = stage_waiting_proxy_version; - } - else - { - control -> ProxyStage = stage_sending_proxy_caches; - } - - break; - } - case stage_waiting_forwarder_version: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_forwarder_version" << "'.\n" - << logofs_flush; - #endif - - int result = ReadForwarderVersion(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - control -> ProxyStage = stage_waiting_forwarder_options; - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_waiting_forwarder_options: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_forwarder_options" << "'.\n" - << logofs_flush; - #endif - - int result = ReadForwarderOptions(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - control -> ProxyStage = stage_sending_proxy_options; - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_waiting_proxy_version: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_proxy_version" << "'.\n" - << logofs_flush; - #endif - - int result = ReadProxyVersion(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - control -> ProxyStage = stage_waiting_proxy_options; - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_waiting_proxy_options: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_proxy_options" << "'.\n" - << logofs_flush; - #endif - - int result = ReadProxyOptions(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - if (control -> ProxyMode == proxy_server) - { - control -> ProxyStage = stage_waiting_proxy_caches; - } - else - { - control -> ProxyStage = stage_sending_proxy_options; - } - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_sending_proxy_caches: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_sending_proxy_caches" << "'.\n" - << logofs_flush; - #endif - - if (SendProxyCaches(proxyFD) < 0) - { - goto handleNegotiationInLoopError; - } - - if (control -> ProxyMode == proxy_server) - { - control -> ProxyStage = stage_operational; - } - else - { - control -> ProxyStage = stage_waiting_proxy_caches; - } - - break; - } - case stage_waiting_proxy_caches: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_waiting_proxy_caches" << "'.\n" - << logofs_flush; - #endif - - int result = ReadProxyCaches(proxyFD); - - if (result == 0) - { - yield = 1; - } - else if (result == 1) - { - if (control -> ProxyMode == proxy_server) - { - control -> ProxyStage = stage_sending_proxy_caches; - } - else - { - control -> ProxyStage = stage_operational; - } - } - else - { - goto handleNegotiationInLoopError; - } - - break; - } - case stage_operational: - { - #ifdef TEST - *logofs << "Loop: Handling negotiation with '" - << "stage_operational" << "'.\n" - << logofs_flush; - #endif - - InitAfterNegotiation(); - - yield = 1; - - break; - } - default: - { - #ifdef PANIC - *logofs << "Loop: PANIC! Unmanaged case '" << control -> ProxyStage - << "' while handling negotiation.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unmanaged case '" << control -> ProxyStage - << "' while handling negotiation.\n"; - - HandleCleanup(); - } - } - } - - // - // Check if the user requested the end of - // the session. - // - - if (CheckAbort() != 0) - { - HandleCleanup(); - } - - // - // Select the proxy descriptor so that we - // can proceed negotiating the session. - // - - FD_SET(proxyFD, &readSet); - - if (proxyFD >= setFDs) - { - setFDs = proxyFD + 1; - } - - setMinTimestamp(selectTs, control -> PingTimeout); - - #ifdef TEST - *logofs << "Loop: Selected proxy FD#" << proxyFD << " in negotiation " - << "phase with timeout of " << selectTs.tv_sec << " S and " - << selectTs.tv_usec << " Ms.\n" << logofs_flush; - #endif - - return; - -handleNegotiationInLoopError: - - #ifdef PANIC - *logofs << "Loop: PANIC! Failure negotiating the session in stage '" - << control -> ProxyStage << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failure negotiating the session in stage '" - << control -> ProxyStage << "'.\n"; - - - if (control -> ProxyMode == proxy_server && - control -> ProxyStage == stage_waiting_proxy_version) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Wrong version or invalid session " - << "authentication cookie.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Wrong version or invalid session " - << "authentication cookie.\n"; - } - - handleTerminatingInLoop(); - - HandleCleanup(); -} - -static void handleTerminatingInLoop() -{ - if (getpid() == lastProxy) - { - if (control -> ProxyStage < stage_terminating) - { - if (agent == NULL) - { - cerr << "Session" << ": Terminating session at '" - << strTimestamp() << "'.\n"; - } - - control -> ProxyStage = stage_terminating; - } - } -} - -static void handleTerminatedInLoop() -{ - if (getpid() == lastProxy) - { - if (control -> ProxyStage < stage_terminated) - { - if (agent == NULL) - { - cerr << "Session" << ": Session terminated at '" - << strTimestamp() << "'.\n"; - } - - control -> ProxyStage = stage_terminated; - } - } -} - -static void handleAlertInLoop() -{ - if (lastAlert.code == 0) - { - return; - } - - // - // Since ProtoStep7 (#issue 108) - // - // Now the remote proxy should always - // be able to handle the alert - // - - if (lastAlert.local == 0) - { - if (proxy != NULL) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Requesting a remote alert with code '" - << lastAlert.code << "'.\n" << logofs_flush; - #endif - - if (proxy -> handleAlert(lastAlert.code) < 0) - { - HandleShutdown(); - } - } - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Handling a local alert with code '" - << lastAlert.code << "'.\n" << logofs_flush; - #endif - - if (control -> ProxyMode == proxy_client) - { - // - // If we are at X client side and server - // proxy is not responding, we don't have - // any possibility to interact with user. - // - - if (lastAlert.code != CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT && - lastAlert.code != RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT && - lastAlert.code != FAILED_PROXY_CONNECTION_CLIENT_ALERT) - { - // - // Let the server proxy show the dialog. - // - - if (proxy != NULL && - proxy -> handleAlert(lastAlert.code) < 0) - { - HandleShutdown(); - } - } - } - else - { - char caption[DEFAULT_STRING_LENGTH]; - - strcpy(caption, ALERT_CAPTION_PREFIX); - - int length = strlen(sessionId); - - // - // Get rid of the trailing MD5 from session id. - // - - if (length > (MD5_LENGTH * 2 + 1) && - *(sessionId + (length - (MD5_LENGTH * 2 + 1))) == '-') - { - strncat(caption, sessionId, length - (MD5_LENGTH * 2 + 1)); - } - else - { - strcat(caption, sessionId); - } - - // - // Use the display to which we are forwarding - // the remote X connections. - // - - char *display = displayHost; - - int replace = 1; - int local = 1; - - const char *message; - const char *type; - - switch (lastAlert.code) - { - case CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT: - { - message = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_STRING; - type = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_TYPE; - - break; - } - case CLOSE_DEAD_X_CONNECTION_SERVER_ALERT: - { - message = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_STRING; - type = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_TYPE; - - break; - } - case CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT: - { - message = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING; - type = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE; - - break; - } - case RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT: - { - message = RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING; - type = RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE; - - break; - } - case CLOSE_UNRESPONSIVE_X_SERVER_ALERT: - { - message = CLOSE_UNRESPONSIVE_X_SERVER_ALERT_STRING; - type = CLOSE_UNRESPONSIVE_X_SERVER_ALERT_TYPE; - - break; - } - case WRONG_PROXY_VERSION_ALERT: - { - message = WRONG_PROXY_VERSION_ALERT_STRING; - type = WRONG_PROXY_VERSION_ALERT_TYPE; - - break; - } - case FAILED_PROXY_CONNECTION_SERVER_ALERT: - { - message = FAILED_PROXY_CONNECTION_SERVER_ALERT_STRING; - type = FAILED_PROXY_CONNECTION_SERVER_ALERT_TYPE; - - break; - } - case MISSING_PROXY_CACHE_ALERT: - { - message = MISSING_PROXY_CACHE_ALERT_STRING; - type = MISSING_PROXY_CACHE_ALERT_TYPE; - - break; - } - case ABORT_PROXY_CONNECTION_ALERT: - { - message = ABORT_PROXY_CONNECTION_ALERT_STRING; - type = ABORT_PROXY_CONNECTION_ALERT_TYPE; - - break; - } - case DISPLACE_MESSAGE_ALERT: - { - message = DISPLACE_MESSAGE_ALERT_STRING; - type = DISPLACE_MESSAGE_ALERT_TYPE; - - break; - } - case GREETING_MESSAGE_ALERT: - { - message = GREETING_MESSAGE_ALERT_STRING; - type = GREETING_MESSAGE_ALERT_TYPE; - - break; - } - case START_RESUME_SESSION_ALERT: - { - message = START_RESUME_SESSION_ALERT_STRING; - type = START_RESUME_SESSION_ALERT_TYPE; - - break; - } - case FAILED_RESUME_DISPLAY_ALERT: - { - message = FAILED_RESUME_DISPLAY_ALERT_STRING; - type = FAILED_RESUME_DISPLAY_ALERT_TYPE; - - break; - } - case FAILED_RESUME_DISPLAY_BROKEN_ALERT: - { - message = FAILED_RESUME_DISPLAY_BROKEN_STRING; - type = FAILED_RESUME_DISPLAY_BROKEN_TYPE; - - break; - } - case FAILED_RESUME_VISUALS_ALERT: - { - message = FAILED_RESUME_VISUALS_ALERT_STRING; - type = FAILED_RESUME_VISUALS_ALERT_TYPE; - - break; - } - case FAILED_RESUME_COLORMAPS_ALERT: - { - message = FAILED_RESUME_COLORMAPS_ALERT_STRING; - type = FAILED_RESUME_COLORMAPS_ALERT_TYPE; - - break; - } - case FAILED_RESUME_PIXMAPS_ALERT: - { - message = FAILED_RESUME_PIXMAPS_ALERT_STRING; - type = FAILED_RESUME_PIXMAPS_ALERT_TYPE; - - break; - } - case FAILED_RESUME_DEPTHS_ALERT: - { - message = FAILED_RESUME_DEPTHS_ALERT_STRING; - type = FAILED_RESUME_DEPTHS_ALERT_TYPE; - - break; - } - case FAILED_RESUME_RENDER_ALERT: - { - message = FAILED_RESUME_RENDER_ALERT_STRING; - type = FAILED_RESUME_RENDER_ALERT_TYPE; - - break; - } - case FAILED_RESUME_FONTS_ALERT: - { - message = FAILED_RESUME_FONTS_ALERT_STRING; - type = FAILED_RESUME_FONTS_ALERT_TYPE; - - break; - } - case INTERNAL_ERROR_ALERT: - { - message = INTERNAL_ERROR_ALERT_STRING; - type = INTERNAL_ERROR_ALERT_TYPE; - - break; - } - case ABORT_PROXY_NEGOTIATION_ALERT: - { - message = ABORT_PROXY_NEGOTIATION_ALERT_STRING; - type = ABORT_PROXY_NEGOTIATION_ALERT_TYPE; - - break; - } - case ABORT_PROXY_SHUTDOWN_ALERT: - { - message = ABORT_PROXY_SHUTDOWN_ALERT_STRING; - type = ABORT_PROXY_SHUTDOWN_ALERT_TYPE; - - break; - } - case FAILED_XDMCP_CONNECTION_ALERT: - { - message = FAILED_XDMCP_CONNECTION_ALERT_STRING; - type = FAILED_XDMCP_CONNECTION_ALERT_TYPE; - - break; - } - default: - { - if (lastAlert.code > LAST_PROTO_STEP_7_ALERT) - { - #ifdef WARNING - *logofs << "Loop: WARNING! An unrecognized alert type '" - << lastAlert.code << "' was requested.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": An unrecognized alert type '" - << lastAlert.code << "' was requested.\n"; - } - #ifdef WARNING - else - { - *logofs << "Loop: WARNING! Ignoring obsolete alert type '" - << lastAlert.code << "'.\n" << logofs_flush; - } - #endif - - message = NULL; - type = NULL; - - replace = 0; - - break; - } - } - - if (replace == 1 && IsRunning(lastDialog)) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Killing the previous dialog with pid '" - << lastDialog << "'.\n" << logofs_flush; - #endif - - // - // The client ignores the TERM signal - // on Windows. - // - - #ifdef __CYGWIN32__ - - KillProcess(lastDialog, "dialog", SIGKILL, 0); - - #else - - KillProcess(lastDialog, "dialog", SIGTERM, 0); - - #endif - - SetNotRunning(lastDialog); - - if (proxy != NULL) - { - proxy -> handleResetAlert(); - } - } - - if (message != NULL && type != NULL) - { - lastDialog = NXTransDialog(caption, message, 0, type, local, display); - - if (IsFailed(lastDialog)) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Can't start the NX dialog process.\n" - << logofs_flush; - #endif - - SetNotRunning(lastDialog); - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "Loop: Dialog started with pid '" - << lastDialog << "'.\n" << logofs_flush; - } - #endif - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "Loop: No new dialog required for code '" - << lastAlert.code << "'.\n" << logofs_flush; - } - #endif - } - } - - // - // Reset state. - // - - lastAlert.code = 0; - lastAlert.local = 0; -} - -static inline void handleSetAgentInLoop(int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs) -{ - #ifdef TEST - *logofs << "Loop: Preparing the masks for the agent descriptors.\n" - << logofs_flush; - #endif - - agent -> saveChannelState(); - - agent -> saveReadMask(&readSet); - agent -> saveWriteMask(&writeSet); - - if (control -> ProxyStage >= stage_operational) - { - if (agent -> remoteCanRead(&readSet) || - agent -> remoteCanWrite(&writeSet) || - agent -> localCanRead() || - agent -> proxyCanRead()) - { - #ifdef TEST - *logofs << "Loop: Setting a null timeout with agent descriptors ready.\n" - << logofs_flush; - #endif - - // - // Force a null timeout so we'll bail out - // of the select immediately. We will ac- - // comodate the result code later. - // - - selectTs.tv_sec = 0; - selectTs.tv_usec = 0; - } - } - - #ifdef TEST - *logofs << "Loop: Clearing the read and write agent descriptors.\n" - << logofs_flush; - #endif - - agent -> clearReadMask(&readSet); - agent -> clearWriteMask(&writeSet); -} - -static inline void handleAgentInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting proxy and local agent descriptors.\n" - << logofs_flush; - #endif - - // - // Check if I/O is possible on the local - // agent or the proxy descriptor. - // - - if (resultFDs >= 0) - { - // - // Save if the proxy can read from the - // the agent descriptor. - // - - agent -> saveChannelState(); - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Values were resultFDs " << resultFDs - << " errorFDs " << errorFDs << " setFDs " - << setFDs << ".\n" << logofs_flush; - #endif - - if (agent -> localCanRead() == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting agent descriptor FD#" << agent -> - getLocalFd() << " as ready to read.\n" - << logofs_flush; - #endif - - agent -> setLocalRead(&readSet, &resultFDs); - } - - #if defined(TEST) || defined(INFO) - - if (agent -> proxyCanRead(&readSet) == 0 && - agent -> proxyCanRead() == 1) - { - *logofs << "Loop: WARNING! Can read from proxy FD#" - << proxyFD << " but the descriptor " - << "is not selected.\n" << logofs_flush; - } - - if (agent -> proxyCanRead(&readSet) == 1) - { - *logofs << "Loop: Setting proxy descriptor FD#" << agent -> - getProxyFd() << " as ready to read.\n" - << logofs_flush; - } - - #endif - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Values are now resultFDs " << resultFDs - << " errorFDs " << errorFDs << " setFDs " - << setFDs << ".\n" << logofs_flush; - #endif - } -} - -static inline void handleAgentLateInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, - fd_set &writeSet, struct timeval &selectTs) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting remote agent descriptors.\n" - << logofs_flush; - #endif - - // - // We reset the masks before calling our select. - // We now set the descriptors that are ready but - // only if they were set in the original mask. - // We do this after having executed our loop as - // we may have produced more data and the agent - // descriptors may have become readable or writ- - // able in the meanwhile. - // - - if (resultFDs >= 0) - { - // - // Save if the proxy can read from the - // the agent descriptor. - // - - agent -> saveChannelState(); - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Values were resultFDs " << resultFDs - << " errorFDs " << errorFDs << " setFDs " - << setFDs << ".\n" << logofs_flush; - #endif - - if (agent -> remoteCanRead(agent -> - getSavedReadMask()) == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting agent descriptor FD#" << agent -> - getRemoteFd() << " as ready to read.\n" - << logofs_flush; - #endif - - agent -> setRemoteRead(&readSet, &resultFDs); - } - - if (agent -> remoteCanWrite(agent -> - getSavedWriteMask()) == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Setting agent descriptor FD#" << agent -> - getRemoteFd() << " as ready to write.\n" - << logofs_flush; - #endif - - agent -> setRemoteWrite(&writeSet, &resultFDs); - } - - #if defined(TEST) || defined(INFO) - *logofs << "Loop: Values are now resultFDs " << resultFDs - << " errorFDs " << errorFDs << " setFDs " - << setFDs << ".\n" << logofs_flush; - #endif - } -} - -static inline void handleReadableInLoop(int &resultFDs, fd_set &readSet) -{ - if (resultFDs > 0) - { - T_channel_type type = channel_none; - - const char *label = NULL; - int domain = -1; - int fd = -1; - - if (tcpFD != -1 && FD_ISSET(tcpFD, &readSet)) - { - type = channel_x11; - label = "X"; - domain = AF_INET; - fd = tcpFD; - - resultFDs--; - } - - if (unixFD != -1 && FD_ISSET(unixFD, &readSet)) - { - type = channel_x11; - label = "X"; - domain = AF_UNIX; - fd = unixFD; - - resultFDs--; - } - - if (cupsFD != -1 && FD_ISSET(cupsFD, &readSet)) - { - type = channel_cups; - label = "CUPS"; - domain = AF_INET; - fd = cupsFD; - - resultFDs--; - } - - if (auxFD != -1 && FD_ISSET(auxFD, &readSet)) - { - // - // Starting from version 1.5.0 we create real X - // connections for the keyboard channel, so they - // can use the fake authorization cookie. This - // means that there is not such a thing like a - // channel_aux anymore. - // - - type = channel_x11; - label = "auxiliary X11"; - domain = AF_INET; - fd = auxFD; - - resultFDs--; - } - - if (smbFD != -1 && FD_ISSET(smbFD, &readSet)) - { - type = channel_smb; - label = "SMB"; - domain = AF_INET; - fd = smbFD; - - resultFDs--; - } - - if (mediaFD != -1 && FD_ISSET(mediaFD, &readSet)) - { - type = channel_media; - label = "media"; - domain = AF_INET; - fd = mediaFD; - - resultFDs--; - } - - if (httpFD != -1 && FD_ISSET(httpFD, &readSet)) - { - type = channel_http; - label = "HTTP"; - domain = AF_INET; - fd = httpFD; - - resultFDs--; - } - - if (fontFD != -1 && FD_ISSET(fontFD, &readSet)) - { - type = channel_font; - label = "font server"; - domain = AF_INET; - fd = fontFD; - - resultFDs--; - } - - if (slaveFD != -1 && FD_ISSET(slaveFD, &readSet)) - { - type = channel_slave; - label = "slave"; - domain = AF_INET; - fd = slaveFD; - - resultFDs--; - } - - if (type != channel_none) - { - int newFD = AcceptConnection(fd, domain, label); - - if (newFD != -1) - { - if (proxy -> handleNewConnection(type, newFD) < 0) - { - #ifdef PANIC - *logofs << "Loop: PANIC! Error creating new " << label - << " connection.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Error creating new " << label - << " connection.\n"; - - close(newFD); - - // - // Don't kill the proxy in the case of an error. - // - // HandleCleanup(); - // - } - else if (proxy -> getReadable(newFD) > 0) - { - // - // Add the descriptor, so we can try - // to read immediately. - // - - #ifdef TEST - *logofs << "Loop: Trying to read immediately " - << "from descriptor FD#" << newFD - << ".\n" << logofs_flush; - #endif - - FD_SET(newFD, &readSet); - - resultFDs++; - } - #ifdef TEST - else - { - *logofs << "Loop: Nothing to read immediately " - << "from descriptor FD#" << newFD - << ".\n" << logofs_flush; - } - #endif - } - } - } - - #ifdef DEBUG - *logofs << "Loop: Going to check the readable descriptors.\n" - << logofs_flush; - #endif - - if (proxy -> handleRead(resultFDs, readSet) < 0) - { - #ifdef TEST - *logofs << "Loop: Failure reading from descriptors " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - HandleShutdown(); - } -} - -static inline void handleWritableInLoop(int &resultFDs, fd_set &writeSet) -{ - #ifdef DEBUG - *logofs << "Loop: Going to check the writable descriptors.\n" - << logofs_flush; - #endif - - if (resultFDs > 0 && proxy -> handleFlush(resultFDs, writeSet) < 0) - { - #ifdef TEST - *logofs << "Loop: Failure writing to descriptors " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - HandleShutdown(); - } -} - -static inline void handleFlushInLoop() -{ - #ifdef DEBUG - *logofs << "Loop: Going to flush any data to the proxy.\n" - << logofs_flush; - #endif - - if (agent == NULL || control -> - FlushPolicy == policy_immediate) - { - #if defined(TEST) || defined(INFO) - - if (usePolicy == -1 && control -> - ProxyMode == proxy_client) - { - *logofs << "Loop: WARNING! Flushing the proxy link " - << "on behalf of the agent.\n" << logofs_flush; - } - - #endif - - if (proxy -> handleFlush() < 0) - { - #ifdef TEST - *logofs << "Loop: Failure flushing the proxy FD#" - << proxyFD << ".\n" << logofs_flush; - #endif - - HandleShutdown(); - } - } -} - -static inline void handleRotateInLoop() -{ - #ifdef DEBUG - *logofs << "Loop: Going to rotate channels " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - proxy -> handleRotate(); -} - -static inline void handleEventsInLoop() -{ - #ifdef DEBUG - *logofs << "Loop: Going to check channel events " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - if (proxy -> handleEvents() < 0) - { - #ifdef TEST - *logofs << "Loop: Failure handling channel events " - << "for proxy FD#" << proxyFD << ".\n" - << logofs_flush; - #endif - - HandleShutdown(); - } -} - -static void handleLogReopenInLoop(T_timestamp &logsTs, T_timestamp &nowTs) -{ - // - // If need to limit the size of the - // log file, check the size at each - // loop. - // - - #ifndef QUOTA - - if (diffTimestamp(logsTs, nowTs) > control -> FileSizeCheckTimeout) - - #endif - { - #ifdef DEBUG - *logofs << "Loop: Checking size of log file '" - << errorsFileName << "'.\n" << logofs_flush; - #endif - - #ifndef MIXED - - if (ReopenLogFile(errorsFileName, logofs, control -> FileSizeLimit) < 0) - { - HandleShutdown(); - } - - #endif - - // - // Reset to current timestamp. - // - - logsTs = nowTs; - } -} - -static inline void handleSetReadInLoop(fd_set &readSet, int &setFDs, struct timeval &selectTs) -{ - proxy -> setReadDescriptors(&readSet, setFDs, selectTs); -} - -static inline void handleSetWriteInLoop(fd_set &writeSet, int &setFDs, struct timeval &selectTs) -{ - proxy -> setWriteDescriptors(&writeSet, setFDs, selectTs); -} - -static void handleSetListenersInLoop(fd_set &readSet, int &setFDs) -{ - // - // Set descriptors of listening sockets. - // - - if (control -> ProxyMode == proxy_client) - { - if (useTcpSocket == 1) - { - FD_SET(tcpFD, &readSet); - - if (tcpFD >= setFDs) - { - setFDs = tcpFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener tcpFD " << tcpFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useUnixSocket == 1) - { - FD_SET(unixFD, &readSet); - - if (unixFD >= setFDs) - { - setFDs = unixFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener unixFD " << unixFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useCupsSocket == 1) - { - FD_SET(cupsFD, &readSet); - - if (cupsFD >= setFDs) - { - setFDs = cupsFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener cupsFD " << cupsFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useAuxSocket == 1) - { - FD_SET(auxFD, &readSet); - - if (auxFD >= setFDs) - { - setFDs = auxFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener auxFD " << auxFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useSmbSocket == 1) - { - FD_SET(smbFD, &readSet); - - if (smbFD >= setFDs) - { - setFDs = smbFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener smbFD " << smbFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useMediaSocket == 1) - { - FD_SET(mediaFD, &readSet); - - if (mediaFD >= setFDs) - { - setFDs = mediaFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener mediaFD " << mediaFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - - if (useHttpSocket == 1) - { - FD_SET(httpFD, &readSet); - - if (httpFD >= setFDs) - { - setFDs = httpFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener httpFD " << httpFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - } - else - { - if (useFontSocket == 1) - { - FD_SET(fontFD, &readSet); - - if (fontFD >= setFDs) - { - setFDs = fontFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener fontFD " << fontFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } - } - - if (useSlaveSocket == 1) - { - FD_SET(slaveFD, &readSet); - - if (slaveFD >= setFDs) - { - setFDs = slaveFD + 1; - } - - #ifdef DEBUG - *logofs << "Loop: Selected listener slaveFD " << slaveFD - << " with setFDs " << setFDs << ".\n" - << logofs_flush; - #endif - } -} diff --git a/nxcomp/MD5.c b/nxcomp/MD5.c deleted file mode 100644 index e49d3cf58..000000000 --- a/nxcomp/MD5.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include "MD5.h" - -#include - -/* - * Try to determine the CPU endianess - * at compile time. - */ - -#if defined(__linux) || defined(__CYGWIN32__) - -#include - -#if (__BYTE_ORDER == __LITTLE_ENDIAN) -#define ARCH_IS_BIG_ENDIAN 0 -#else -#define ARCH_IS_BIG_ENDIAN 1 -#endif - -#endif /* #if defined(__linux) || defined(__CYGWIN32__) */ - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} diff --git a/nxcomp/MD5.h b/nxcomp/MD5.h deleted file mode 100644 index 698c995d8..000000000 --- a/nxcomp/MD5.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/* Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ diff --git a/nxcomp/Makefile.am b/nxcomp/Makefile.am new file mode 100644 index 000000000..ae5991c3d --- /dev/null +++ b/nxcomp/Makefile.am @@ -0,0 +1,21 @@ +SUBDIRS = src + +pkgconfig_DATA = nxcomp.pc + +MAINTAINERCLEANFILES = \ + $(srcdir)/autom4te.cache/* \ + $(srcdir)/build-aux/* \ + $(srcdir)/Makefile.in \ + $(srcdir)/src/Makefile.in \ + $(srcdir)/aclocal.m4 \ + $(srcdir)/config.h.in \ + $(srcdir)/config.h.in~ \ + $(srcdir)/configure \ + $(srcdir)/m4/libtool.m4 \ + $(srcdir)/m4/lt~obsolete.m4 \ + $(srcdir)/m4/ltoptions.m4 \ + $(srcdir)/m4/ltsugar.m4 \ + $(srcdir)/m4/ltversion.m4 \ + $(NULL) + +DISTCLEANFILES=$(MAINTAINERCLEANFILES) diff --git a/nxcomp/Makefile.in b/nxcomp/Makefile.in deleted file mode 100644 index f18875524..000000000 --- a/nxcomp/Makefile.in +++ /dev/null @@ -1,333 +0,0 @@ -#/**************************************************************************/ -#/* */ -#/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -#/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -#/* Copyright (c) 2014-2016 Ulrich Sibiller */ -#/* Copyright (c) 2014-2016 Mihai Moldovan */ -#/* Copyright (c) 2011-2016 Mike Gabriel */ -#/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -#/* */ -#/* NXCOMP, NX protocol compression and NX extensions to this software */ -#/* are copyright of the aforementioned persons and companies. */ -#/* */ -#/* Redistribution and use of the present software is allowed according */ -#/* to terms specified in the file LICENSE.nxcomp which comes in the */ -#/* source distribution. */ -#/* */ -#/* All rights reserved. */ -#/* */ -#/* NOTE: This software has received contributions from various other */ -#/* contributors, only the core maintainers and supporters are listed as */ -#/* copyright holders. Please contact us, if you feel you should be listed */ -#/* as copyright holder, as well. */ -#/* */ -#/**************************************************************************/ - -# -# Get these values from the configure script. The -# version printed by the program should be derived -# from the CHANGELOG. For example we may use the -# following command: -# -# head -n 3 CHANGELOG | grep 'nxcomp-' | cut -d '-' -f 2-3 -# - -VERSION=@VERSION@ -LIBVERSION=@LIBVERSION@ - -# -# We would really like to enable all warnings, -Wredundant-decls, -# though, gives a warning caused by pthread.h and unistd.h and -# GCC 3.4 was changed in a way that it now complains about some -# of the -W directives we used before (-Wmissing-declarations, -# -Wnested-externs, -Wstrict-prototypes and -Wmissing-prototypes). -# - -CXX = @CXX@ -CXXFLAGS = @CXXFLAGS@ @X_CFLAGS@ @DEFS@ \ - -Wall -Wpointer-arith -CXXINCLUDES = -CXXDEFINES = - -CPPFLAGS = @CPPFLAGS@ - -# -# C programs have their own CFLAGS. -# - -CC = @CC@ -CCFLAGS = @CFLAGS@ @X_CFLAGS@ @DEFS@ \ - -Wall -Wpointer-arith -CCINCLUDES = -CCDEFINES = - -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ - -# -# Other autoconfigured settings, not used at the moment. -# - -srcdir = @srcdir@ -prefix = @prefix@ -datarootdir = @datarootdir@ -datadir = @datadir@ -exec_prefix = @exec_prefix@ -bindir = @bindir@ -man1dir = @mandir@/man1 -VPATH = @srcdir@ -libdir = @libdir@ -includedir = @includedir@ -pkgconfigdir = @pkgconfigdir@ - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_LINK = cp -av -DESTDIR = -RM_FILE = rm -f - -# -# This should be autodetected. -# - -MAKEDEPEND = @MAKEDEPEND@ -DEPENDINCLUDES = -I/usr/include/c++ -I/usr/include/g++ -I/usr/include/g++-3 - -.SUFFIXES: .cpp.c - -.cpp.o: - $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $(CXXINCLUDES) $(CXXDEFINES) $< -.c.o: - $(CC) -c $(CPPFLAGS) $(CCFLAGS) $(CCINCLUDES) $(CCDEFINES) $< - -LIBRARY = Xcomp - -LIBNAME = lib$(LIBRARY) -ifeq ($(shell uname),Darwin) -LIBFULL = lib$(LIBRARY).$(VERSION).dylib -LIBLOAD = lib$(LIBRARY).$(LIBVERSION).dylib -LIBSHARED = lib$(LIBRARY).dylib -COMP_VER = $(shell echo '$(VERSION)' | cut -d '.' -f 1-3) -LIBFLAGS = -install_name $(libdir)/$(LIBLOAD) -compatibility_version $(LIBVERSION) -current_version $(COMP_VER) -else -LIBFULL = lib$(LIBRARY).so.$(VERSION) -LIBLOAD = lib$(LIBRARY).so.$(LIBVERSION) -LIBSHARED = lib$(LIBRARY).so -LIBFLAGS = -endif -LIBARCHIVE = lib$(LIBRARY).a - -LIBCYGSHARED = cyg$(LIBRARY).dll -LIBCYGARCHIVE = lib$(LIBRARY).dll.a - -all: depend @ALL@ - -MSRC = - -CSRC = MD5.c \ - Pack.c \ - Vars.c \ - Version.c - -CXXSRC = Loop.cpp \ - Children.cpp \ - Control.cpp \ - Misc.cpp \ - Socket.cpp \ - Fork.cpp \ - Pipe.cpp \ - List.cpp \ - Keeper.cpp \ - Timestamp.cpp \ - Transport.cpp \ - Statistics.cpp \ - Auth.cpp \ - Agent.cpp \ - Proxy.cpp \ - Channel.cpp \ - Message.cpp \ - Split.cpp \ - ClientProxy.cpp \ - ServerProxy.cpp \ - OpcodeStore.cpp \ - ClientStore.cpp \ - ServerStore.cpp \ - ChannelCache.cpp \ - ClientCache.cpp \ - ServerCache.cpp \ - ClientChannel.cpp \ - ServerChannel.cpp \ - GenericChannel.cpp \ - ChannelEndPoint.cpp \ - ReadBuffer.cpp \ - ProxyReadBuffer.cpp \ - ClientReadBuffer.cpp \ - ServerReadBuffer.cpp \ - GenericReadBuffer.cpp \ - EncodeBuffer.cpp \ - DecodeBuffer.cpp \ - WriteBuffer.cpp \ - SequenceQueue.cpp \ - IntCache.cpp \ - CharCache.cpp \ - XidCache.cpp \ - ActionCache.cpp \ - BlockCache.cpp \ - BlockCacheSet.cpp \ - StaticCompressor.cpp \ - Unpack.cpp \ - Alpha.cpp \ - Colormap.cpp \ - Jpeg.cpp \ - Pgn.cpp \ - Bitmap.cpp \ - Rgb.cpp \ - Rle.cpp \ - Z.cpp \ - ChangeProperty.cpp \ - SendEvent.cpp \ - ChangeGC.cpp \ - CreateGC.cpp \ - CreatePixmap.cpp \ - SetClipRectangles.cpp \ - CopyArea.cpp \ - PolyLine.cpp \ - PolySegment.cpp \ - PolyFillRectangle.cpp \ - PutImage.cpp \ - TranslateCoords.cpp \ - GetImage.cpp \ - ClearArea.cpp \ - ConfigureWindow.cpp \ - PolyText8.cpp \ - PolyText16.cpp \ - ImageText8.cpp \ - ImageText16.cpp \ - PolyPoint.cpp \ - PolyFillArc.cpp \ - PolyArc.cpp \ - FillPoly.cpp \ - InternAtom.cpp \ - GetProperty.cpp \ - SetUnpackGeometry.cpp \ - SetUnpackColormap.cpp \ - SetUnpackAlpha.cpp \ - PutPackedImage.cpp \ - ShapeExtension.cpp \ - RenderExtension.cpp \ - GenericRequest.cpp \ - QueryFontReply.cpp \ - ListFontsReply.cpp \ - GetImageReply.cpp \ - GetPropertyReply.cpp \ - GenericReply.cpp \ - RenderGenericRequest.cpp \ - RenderCreatePicture.cpp \ - RenderChangePicture.cpp \ - RenderFreePicture.cpp \ - RenderPictureClip.cpp \ - RenderPictureTransform.cpp \ - RenderPictureFilter.cpp \ - RenderCreateGlyphSet.cpp \ - RenderFreeGlyphSet.cpp \ - RenderAddGlyphs.cpp \ - RenderComposite.cpp \ - RenderCompositeGlyphs.cpp \ - RenderFillRectangles.cpp \ - RenderTrapezoids.cpp \ - RenderTriangles.cpp - -MOBJ = $(MSRC:.c=.o) -COBJ = $(CSRC:.c=.o) -CXXOBJ = $(CXXSRC:.cpp=.o) - -$(LIBFULL): $(CXXOBJ) $(COBJ) - $(CXX) -o $@ $(LDFLAGS) $(LIBFLAGS) $(CXXOBJ) $(COBJ) $(LIBS) - -$(LIBLOAD): $(LIBFULL) - rm -f $(LIBLOAD) - ln -s $(LIBFULL) $(LIBLOAD) - -$(LIBSHARED): $(LIBFULL) - rm -f $(LIBSHARED) - ln -s $(LIBFULL) $(LIBSHARED) - -$(LIBARCHIVE): $(CXXOBJ) $(COBJ) - rm -f $(LIBARCHIVE) - ar clq $(LIBARCHIVE) $(CXXOBJ) $(COBJ) - ranlib $(LIBARCHIVE) - -$(LIBCYGSHARED): $(LIBARCHIVE) - $(CC) -shared -o $(LIBCYGSHARED) \ - -Wl,--out-implib=$(LIBCYGARCHIVE) \ - -Wl,--export-all-symbols \ - -Wl,--enable-auto-import \ - -Wl,--whole-archive $(LIBARCHIVE) \ - -Wl,--no-whole-archive $(LIBS) \ - $(LDFLAGS) - -$(LIBCYGARCHIVE): $(LIBCYGSHARED) - -depends: depend.status - -depend: depend.status - -depend.status: - if [ -n "$(MAKEDEPEND)" ] && [ -x "$(MAKEDEPEND)" ] ; then \ - $(MAKEDEPEND) $(CXXINCLUDES) $(CCINCLUDES) \ - $(DEPENDINCLUDES) -f Makefile $(MSRC) $(CSRC) \ - $(CXXSRC) 2>/dev/null; \ - fi - touch depend.status - -install: install.bin install.lib install.man - -install.bin: - -install.lib: all - ./mkinstalldirs $(DESTDIR)${libdir} - ./mkinstalldirs $(DESTDIR)${includedir}/nx - ./mkinstalldirs $(DESTDIR)${pkgconfigdir} - $(INSTALL_DATA) $(LIBFULL) $(DESTDIR)${libdir} - $(INSTALL_LINK) $(LIBLOAD) $(DESTDIR)${libdir} - $(INSTALL_LINK) $(LIBSHARED) $(DESTDIR)${libdir} - $(INSTALL_DATA) $(LIBARCHIVE) $(DESTDIR)${libdir} - $(INSTALL_DATA) MD5.h $(DESTDIR)${includedir}/nx - $(INSTALL_DATA) NX.h $(DESTDIR)${includedir}/nx - $(INSTALL_DATA) NXalert.h $(DESTDIR)${includedir}/nx - $(INSTALL_DATA) NXpack.h $(DESTDIR)${includedir}/nx - $(INSTALL_DATA) NXproto.h $(DESTDIR)${includedir}/nx - $(INSTALL_DATA) NXvars.h $(DESTDIR)${includedir}/nx - $(INSTALL_DATA) nxcomp.pc $(DESTDIR)${pkgconfigdir} - echo "Running ldconfig tool, this may take a while..." && ldconfig || true - -install.man: - -uninstall: uninstall.bin uninstall.lib uninstall.man - -uninstall.bin: - -uninstall.lib: - $(RM_FILE) $(DESTDIR)${libdir}/$(LIBFULL) - $(RM_FILE) $(DESTDIR)${libdir}/$(LIBLOAD) - $(RM_FILE) $(DESTDIR)${libdir}/$(LIBSHARED) - $(RM_FILE) $(DESTDIR)${libdir}/$(LIBARCHIVE) - $(RM_FILE) $(DESTDIR)${includedir}/nx/NXalert.h - $(RM_FILE) $(DESTDIR)${includedir}/nx/NX.h - $(RM_FILE) $(DESTDIR)${includedir}/nx/NXpack.h - $(RM_FILE) $(DESTDIR)${includedir}/nx/NXproto.h - $(RM_FILE) $(DESTDIR)${includedir}/nx/NXvars.h - $(RM_FILE) $(DESTDIR)${includedir}/nx/MD5.h - $(RM_FILE) $(DESTDIR)${pkgconfigdir}/nxcomp.pc - echo "Running ldconfig tool, this may take a while..." && ldconfig || true - -uninstall.man: - -clean: - -rm -f *~ *.o *.bak *.orig *.rej st?????? core core.* *.out.* *.pc \ - @ALL@ - -distclean: clean - -rm -rf autom4te.cache config.status config.log \ - config.cache depend.status Makefile tags configure diff --git a/nxcomp/Message.cpp b/nxcomp/Message.cpp deleted file mode 100644 index 530b6b5a8..000000000 --- a/nxcomp/Message.cpp +++ /dev/null @@ -1,2339 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include - -#include - -#include "Misc.h" - -// -// We need channel's cache data. -// - -#include "Message.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. You also -// need to define DUMP in Misc.cpp -// if DUMP is defined here. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Define this to log when messages -// are allocated and deallocated. -// - -#undef REFERENCES - -// -// Keep track of how many bytes are -// occupied by cache. -// - -int MessageStore::totalLocalStorageSize_ = 0; -int MessageStore::totalRemoteStorageSize_ = 0; - -// -// These are used for reference count. -// - -#ifdef REFERENCES - -int Message::references_ = 0; -int MessageStore::references_ = 0; - -#endif - -// -// Here are the methods to handle cached messages. -// - -MessageStore::MessageStore(StaticCompressor *compressor) - - : compressor_(compressor) -{ - // - // Public members. - // - - enableCache = MESSAGE_ENABLE_CACHE; - enableData = MESSAGE_ENABLE_DATA; - enableSplit = MESSAGE_ENABLE_SPLIT; - enableCompress = MESSAGE_ENABLE_COMPRESS; - - dataLimit = MESSAGE_DATA_LIMIT; - dataOffset = MESSAGE_DATA_OFFSET; - - cacheSlots = MESSAGE_CACHE_SLOTS; - cacheThreshold = MESSAGE_CACHE_THRESHOLD; - cacheLowerThreshold = MESSAGE_CACHE_LOWER_THRESHOLD; - - #ifdef TEST - *logofs << "MessageStore: Static compressor is at " - << compressor_ << ".\n" << logofs_flush; - #endif - - md5_state_ = new md5_state_t(); - - #ifdef DEBUG - *logofs << "MessageStore: Created MD5 state for object at " - << this << ".\n" << logofs_flush; - #endif - - lastAdded = cacheSlots; - lastHit = 0; - lastRemoved = 0; - lastRated = nothing; - lastAction = is_discarded; - - // - // Private members. - // - - localStorageSize_ = 0; - remoteStorageSize_ = 0; - - #ifdef TEST - *logofs << "MessageStore: Size of total cache is " - << totalLocalStorageSize_ << " bytes at local side and " - << totalRemoteStorageSize_ << " bytes at remote side.\n" - << logofs_flush; - #endif - - messages_ = new T_messages(); - checksums_ = new T_checksums(); - - temporary_ = NULL; - - #ifdef REFERENCES - - references_++; - - *logofs << "MessageStore: Created new store at " - << this << "out of " << references_ - << " allocated stores.\n" << logofs_flush; - - #endif -} - -MessageStore::~MessageStore() -{ - // - // The virtual destructor of specialized class - // must get rid of both messages in container - // and temporary. - // - - #ifdef DEBUG - *logofs << "MessageStore: Deleting MD5 state for object at " - << this << ".\n" << logofs_flush; - #endif - - delete md5_state_; - - delete messages_; - delete checksums_; - - // - // Update the static members tracking - // size of total memory allocated for - // all stores. - // - - totalLocalStorageSize_ -= localStorageSize_; - totalRemoteStorageSize_ -= remoteStorageSize_; - - #ifdef TEST - *logofs << "MessageStore: Size of total cache is " - << totalLocalStorageSize_ << " bytes at local side and " - << totalRemoteStorageSize_ << " bytes at remote side.\n" - << logofs_flush; - #endif - - #ifdef REFERENCES - - references_--; - - *logofs << "MessageStore: Deleted store at " - << this << " out of " << references_ - << " allocated stores.\n" << logofs_flush; - - #endif -} - -// -// Here are the methods to parse and cache -// messages in the message stores. -// - -int MessageStore::parse(Message *message, int split, const unsigned char *buffer, - unsigned int size, T_checksum_action checksumAction, - T_data_action dataAction, int bigEndian) -{ - // - // Save the message size as received on the link. - // This information will be used to create an ap- - // propriate buffer at the time the message will - // be unparsed. - // - - message -> size_ = size; - message -> i_size_ = identitySize(buffer, size); - message -> c_size_ = 0; - - validateSize(size); - - if (checksumAction == use_checksum) - { - beginChecksum(message); - - parseIdentity(message, buffer, size, bigEndian); - - identityChecksum(message, buffer, size, bigEndian); - - parseData(message, split, buffer, size, checksumAction, dataAction, bigEndian); - - endChecksum(message); - } - else - { - parseIdentity(message, buffer, size, bigEndian); - - parseData(message, split, buffer, size, checksumAction, dataAction, bigEndian); - } - - return 1; -} - -int MessageStore::parse(Message *message, const unsigned char *buffer, - unsigned int size, const unsigned char *compressedData, - const unsigned int compressedDataSize, - T_checksum_action checksumAction, - T_data_action dataAction, int bigEndian) -{ - int offset = identitySize(buffer, size); - - message -> size_ = size; - message -> i_size_ = offset; - message -> c_size_ = compressedDataSize + offset; - - validateSize(message -> size_ - offset, compressedDataSize); - - if (checksumAction == use_checksum) - { - beginChecksum(message); - - parseIdentity(message, buffer, size, bigEndian); - - identityChecksum(message, buffer, size, bigEndian); - - parseData(message, buffer, size, compressedData, compressedDataSize, - checksumAction, dataAction, bigEndian); - - endChecksum(message); - } - else - { - parseIdentity(message, buffer, size, bigEndian); - - parseData(message, buffer, size, compressedData, compressedDataSize, - checksumAction, dataAction, bigEndian); - } - - return 1; -} - -int MessageStore::parseData(Message *message, int split, const unsigned char *buffer, - unsigned int size, T_checksum_action checksumAction, - T_data_action dataAction, int bigEndian) -{ - if ((int) size > message -> i_size_) - { - unsigned int dataSize = size - message -> i_size_; - - if (checksumAction == use_checksum) - { - #ifdef DEBUG - *logofs << name() << ": Calculating checksum of object at " - << message << " with data size " << dataSize - << ".\n" << logofs_flush; - #endif - - dataChecksum(message, buffer, size, bigEndian); - } - - if (dataAction == discard_data) - { - #ifdef DEBUG - *logofs << name() << ": Discarded " << dataSize - << " bytes of plain data. Real size is " - << message -> size_ << " compressed size is " - << message -> c_size_ << ".\n" << logofs_flush; - #endif - - return 1; - } - - // - // Accept anyway data beyond the - // expected limit. - // - - #ifdef TEST - - if (dataSize > (unsigned int) dataLimit) - { - *logofs << name() << ": WARNING! Data is " << dataSize - << " bytes. Ignoring the established limit.\n" - << logofs_flush; - } - - #endif - - if (dataSize != message -> data_.size()) - { - #ifdef DEBUG - *logofs << name() << ": Data will be resized from " - << message -> data_.size() << " to hold a plain buffer of " - << dataSize << " bytes.\n" << logofs_flush; - #endif - - message -> data_.clear(); - - message -> data_.resize(dataSize); - } - - if (split == 0) - { - memcpy(message -> data_.begin(), buffer + message -> i_size_, dataSize); - } - #ifdef TEST - else - { - *logofs << name() << ": Not copied " << dataSize - << " bytes of fake data for the split message.\n" - << logofs_flush; - } - #endif - - #ifdef DEBUG - *logofs << name() << ": Parsed " << dataSize - << " bytes of plain data. Real size is " - << message -> size_ << " compressed size is " - << message -> c_size_ << ".\n" << logofs_flush; - #endif - } - - return 1; -} - -// -// Store the data part in compressed format. -// - -int MessageStore::parseData(Message *message, const unsigned char *buffer, - unsigned int size, const unsigned char *compressedData, - const unsigned int compressedDataSize, - T_checksum_action checksumAction, - T_data_action dataAction, int bigEndian) -{ - if ((int) size > message -> i_size_) - { - unsigned int dataSize = size - message -> i_size_; - - if (checksumAction == use_checksum) - { - #ifdef DEBUG - *logofs << name() << ": Calculating checksum of object at " - << message << " with data size " << dataSize - << ".\n" << logofs_flush; - #endif - - dataChecksum(message, buffer, size, bigEndian); - } - - if (dataAction == discard_data) - { - #ifdef DEBUG - *logofs << name() << ": Discarded " << dataSize - << " bytes of compressed data. Real size is " - << message -> size_ << " compressed size is " - << message -> c_size_ << ".\n" << logofs_flush; - #endif - - return 1; - } - - #ifdef WARNING - if (dataSize > (unsigned int) dataLimit) - { - *logofs << name() << ": WARNING! Data is " << dataSize - << " bytes. Ignoring the established limit!\n" - << logofs_flush; - } - #endif - - dataSize = compressedDataSize; - - if (dataSize != message -> data_.size()) - { - #ifdef DEBUG - *logofs << name() << ": Data will be resized from " - << message -> data_.size() << " to hold a compressed buffer of " - << dataSize << " bytes.\n" << logofs_flush; - #endif - - message -> data_.clear(); - - message -> data_.resize(compressedDataSize); - } - - memcpy(message -> data_.begin(), compressedData, compressedDataSize); - - #ifdef DEBUG - *logofs << name() << ": Parsed " << dataSize - << " bytes of compressed data. Real size is " - << message -> size_ << " compressed size is " - << message -> c_size_ << ".\n" << logofs_flush; - #endif - } - - return 1; -} - -int MessageStore::unparseData(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) -{ - // - // Copy data, if any, to the buffer. - // - - if ((int) size > message -> i_size_) - { - // - // Check if message has been stored - // in compressed format. - // - - if (message -> c_size_ == 0) - { - memcpy(buffer + message -> i_size_, message -> data_.begin(), size - message -> i_size_); - - #ifdef DEBUG - *logofs << name() << ": Unparsed " << message -> size_ - message -> i_size_ - << " bytes of data to a buffer of " << message -> size_ - message -> i_size_ - << ".\n" << logofs_flush; - #endif - } - else - { - #ifdef DEBUG - *logofs << name() << ": Using static compressor at " << (void *) compressor_ - << ".\n" << logofs_flush; - #endif - - if (compressor_ -> - decompressBuffer(buffer + message -> i_size_, - size - message -> i_size_, - message -> data_.begin(), - message -> c_size_ - message -> i_size_) < 0) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Data decompression failed.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Data decompression failed.\n"; - - return -1; - } - - #ifdef DEBUG - *logofs << name() << ": Unparsed " << message -> c_size_ - message -> i_size_ - << " bytes of compressed data to a buffer of " - << message -> size_ - message -> i_size_ << ".\n" << logofs_flush; - #endif - } - } - - // - // We could write size to the buffer but this - // is something the channel class is doing by - // itself. - // - // PutUINT(size >> 2, buffer + 2, bigEndian); - // - - return 1; -} - -void MessageStore::dumpData(const Message *message) const -{ - #ifdef DUMP - - *logofs << name() << ": Dumping enumerated data:\n" << logofs_flush; - - DumpData(message -> data_.begin(), message -> data_.size()); - - #endif - - #ifdef DUMP - - *logofs << name() << ": Dumping checksum data:\n" << logofs_flush; - - DumpData(message -> md5_digest_, MD5_LENGTH); - - #endif -} - -T_checksum MessageStore::getChecksum(const unsigned char *buffer, - unsigned int size, int bigEndian) -{ - Message *message = getTemporary(); - - message -> size_ = size; - message -> i_size_ = identitySize(buffer, size); - message -> c_size_ = 0; - - validateSize(size); - - beginChecksum(message); - - // - // We don't need to extract the identity - // data from the buffer. - // - // parseIdentity(message, buffer, size, bigEndian); - // - - identityChecksum(message, buffer, size, bigEndian); - - parseData(message, 0, buffer, size, use_checksum, discard_data, bigEndian); - - endChecksum(message); - - // - // The caller will have to explicitly - // deallocated the memory after use. - // - - T_checksum checksum = new md5_byte_t[MD5_LENGTH]; - - memcpy(checksum, message -> md5_digest_, MD5_LENGTH); - - return checksum; -} - -int MessageStore::clean(T_checksum_action checksumAction) -{ - int position = lastRemoved + 1; - - if (position >= cacheSlots) - { - position = 0; - } - - #ifdef DEBUG - *logofs << name() << ": Searching a message to remove " - << "starting at position " << position - << " with " << checksums_ -> size() - << " elements in cache.\n" - << logofs_flush; - #endif - - while (position != lastRemoved) - { - #ifdef DEBUG - *logofs << name() << ": Examining position " - << position << ".\n" << logofs_flush; - #endif - - if ((*messages_)[position] != NULL) - { - if (getRating((*messages_)[position], rating_for_clean) == 0) - { - break; - } - else - { - untouch((*messages_)[position]); - } - } - - if (++position == cacheSlots) - { - #ifdef DEBUG - *logofs << name() << ": Rolled position at " - << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - position = 0; - } - } - - // - // If no message is a good candidate, - // then try the object at the next slot - // in respect to last element removed. - // - - if (position == lastRemoved) - { - position = lastRemoved + 1; - - if (position >= cacheSlots) - { - position = 0; - } - - if ((*messages_)[position] == NULL || - (*messages_)[position] -> locks_ != 0) - { - #ifdef DEBUG - *logofs << name() << ": WARNING! No message found " - << "to be actually removed.\n" - << logofs_flush; - #endif - - return nothing; - } - - #ifdef DEBUG - *logofs << name() << ": WARNING! Assuming object " - << "at position " << position << ".\n" - << logofs_flush; - #endif - } - - return position; -} - -// -// This is the insertion method used at local side -// side. Cache at remote side side will be kept in -// sync by telling the to other party where to -// store the message. -// - -int MessageStore::findOrAdd(Message *message, T_checksum_action checksumAction, - T_data_action dataAction, int &added, int &locked) -{ - if (checksumAction != use_checksum) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Internal error in context [A]. " - << "Cannot find or add message to repository " - << "without using checksum.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Internal error in context [A]. " - << "Cannot find or add message to repository " - << "without using checksum.\n"; - - HandleAbort(); - } - - // - // Set added to true only if message - // is inserted in cache. - // - - added = 0; - locked = 0; - - // - // First of all figure out where to - // store this object. - // - - #ifdef DEBUG - *logofs << name() << ": Searching an empty slot " - << "with last rated " << lastRated << " and " - << "last added " << lastAdded << ".\n" - << logofs_flush; - #endif - - int position = lastRated; - - if (position == nothing) - { - position = lastAdded + 1; - - if (position >= cacheSlots) - { - position = 0; - } - - #ifdef DEBUG - *logofs << name() << ": Searching an empty slot " - << "starting at position " << position - << " with " << checksums_ -> size() - << " elements in cache.\n" - << logofs_flush; - #endif - - while (position != lastAdded) - { - #ifdef DEBUG - *logofs << name() << ": Examining position " - << position << ".\n" << logofs_flush; - #endif - - if ((*messages_)[position] == NULL) - { - break; - } - else if (getRating((*messages_)[position], rating_for_insert) == 0) - { - break; - } - else - { - untouch((*messages_)[position]); - } - - if (++position == cacheSlots) - { - #ifdef DEBUG - *logofs << name() << ": Rolled position at " - << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - position = 0; - } - } - } - #ifdef DEBUG - else - { - *logofs << name() << ": Using last rated position " - << position << ".\n" << logofs_flush; - } - #endif - - // - // If we made an extensive check but did not - // find neither a free slot or a message to - // replace, assume slot at next position in - // respect to last added. This can happen if - // all objects in repository have got an hit - // recently. - // - - if (position == lastAdded) - { - position = lastAdded + 1; - - if (position >= cacheSlots) - { - position = 0; - } - - #ifdef DEBUG - *logofs << name() << ": WARNING! Assuming slot " - << "at position " << position << ".\n" - << logofs_flush; - #endif - } - #ifdef DEBUG - else - { - *logofs << name() << ": Found candidate slot " - << "at position " << position << ".\n" - << logofs_flush; - } - #endif - - // - // Save the search result so if the message - // is found in cache, we can use the slot - // at next run. - // - - lastRated = position; - - if ((*messages_)[position] != NULL && - (*messages_)[position] -> locks_ != 0) - { - #ifdef WARNING - *logofs << name() << ": WARNING! Insertion at position " - << position << " would replace a locked message. " - << "Forcing channel to discard the message.\n" - << logofs_flush; - #endif - - #ifdef TEST - *logofs << name() << ": Invalidating rating of object " - << "at position " << position << ".\n" - << logofs_flush; - #endif - - return (lastRated = nothing); - } - - if (checksumAction == use_checksum) - { - T_checksum checksum = getChecksum(message); - - #ifdef TEST - *logofs << name() << ": Searching checksum [" - << DumpChecksum(checksum) << "] in repository.\n" - << logofs_flush; - - #endif - - pair result; - - result = checksums_ -> insert(T_checksums::value_type(checksum, position)); - - // - // Message was found in cache or - // insertion couldn't take place. - // - - if (result.second == 0) - { - if (result.first == checksums_ -> end()) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Failed to insert object " - << "in the cache.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to insert object of type " - << name() << " in the cache.\n"; - - return nothing; - } - - // - // Message is in cache. - // - - #ifdef TEST - *logofs << name() << ": Object is already in cache " - << "at position " << (result.first) -> second - << ".\n" << logofs_flush; - #endif - - #ifdef DEBUG - - printStorageSize(); - - #endif - - // - // Message is locked, probably because - // it has not completely recomposed at - // remote side after a split. - // - - if ((*messages_)[(result.first) -> second] -> locks_ != 0) - { - #ifdef TEST - *logofs << name() << ": WARNING! Object at position " - << (result.first) -> second << " is locked.\n" - << logofs_flush; - #endif - - locked = 1; - } - - // - // Object got a hit, so prevent - // its removal. - // - - if (lastRated == (result.first) -> second) - { - #ifdef TEST - *logofs << name() << ": Resetting rating of object " - << "at position " << (result.first) -> second - << ".\n" << logofs_flush; - #endif - - lastRated = nothing; - } - - return (result.first) -> second; - } - - #ifdef DEBUG - *logofs << name() << ": Could not find message in cache.\n" - << logofs_flush; - #endif - } - - // - // Message not found in hash table (or insertion - // of checksum in hash table was not requested). - // Message was added to cache. - // - - added = 1; - - // - // Log data about the missed message. - // - - #ifdef TEST - - if (opcode() == X_PutImage || opcode() == X_NXPutPackedImage) - { - #ifdef WARNING - *logofs << name() << ": WARNING! Dumping identity of " - << "missed image object of type " << name() - << ".\n" << logofs_flush; - #endif - - dumpIdentity(message); - } - - #endif - - if ((*messages_)[position] != NULL) - { - #ifdef DEBUG - *logofs << name() << ": The message replaces " - << "the old one at position " << position - << ".\n" << logofs_flush; - #endif - - remove(position, checksumAction, dataAction); - } - - (*messages_)[position] = message; - - // - // We used the slot. Perform a new - // search at next run. - // - - lastRated = nothing; - - #ifdef TEST - *logofs << name() << ": Stored message object of size " - << plainSize(position) << " (" << message -> size_ - << "/" << message -> c_size_ << ") at position " - << position << ".\n" << logofs_flush; - #endif - - unsigned int localSize; - unsigned int remoteSize; - - storageSize(message, localSize, remoteSize); - - localStorageSize_ += localSize; - remoteStorageSize_ += remoteSize; - - totalLocalStorageSize_ += localSize; - totalRemoteStorageSize_ += remoteSize; - - #ifdef DEBUG - - printStorageSize(); - - #endif - - // - // Set hits and timestamp at insertion in cache. - // - - message -> hits_ = control -> StoreHitsAddBonus; - message -> last_ = (getTimestamp()).tv_sec; - - message -> locks_ = 0; - - #ifdef DEBUG - *logofs << name() << ": Set last hit of object at " - << strMsTimestamp() << " with a bonus of " - << message -> hits_ << ".\n" << logofs_flush; - #endif - - return position; -} - -// -// Add a parsed message to repository. It is normally used -// at decoding side or at encoding side when we load store -// from disk. To handle messages coming from network, the -// encoding side uses the optimized method findOrAdd(). -// - -int MessageStore::add(Message *message, const int position, - T_checksum_action checksumAction, T_data_action dataAction) -{ - if (position < 0 || position >= cacheSlots) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Cannot add a message " - << "at non existing position " << position - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot add a message " - << "at non existing position " << position - << ".\n"; - - HandleAbort(); - } - - if ((*messages_)[position] != NULL) - { - #ifdef DEBUG - *logofs << name() << ": The message will replace " - << "the old one at position " << position - << ".\n" << logofs_flush; - #endif - - remove(position, checksumAction, dataAction); - } - - #ifdef DEBUG - *logofs << name() << ": Inserting object in repository at position " - << position << ".\n" << logofs_flush; - #endif - - (*messages_)[position] = message; - - // - // Get the object's checksum value - // and insert it in the table. - // - - if (checksumAction == use_checksum) - { - #ifdef DEBUG - *logofs << name() << ": Inserting object's checksum in repository.\n"; - #endif - - T_checksum checksum = getChecksum(message); - - checksums_ -> insert(T_checksums::value_type(checksum, position)); - } - - #ifdef DEBUG - *logofs << name() << ": Stored message object of size " - << plainSize(position) << " (" << message -> size_ - << "/" << message -> c_size_ << ") at position " - << position << ".\n" << logofs_flush; - #endif - - unsigned int localSize; - unsigned int remoteSize; - - storageSize(message, localSize, remoteSize); - - localStorageSize_ += localSize; - remoteStorageSize_ += remoteSize; - - totalLocalStorageSize_ += localSize; - totalRemoteStorageSize_ += remoteSize; - - #ifdef DEBUG - - printStorageSize(); - - #endif - - // - // Set hits and timestamp at insertion in cache. - // - - message -> hits_ = control -> StoreHitsAddBonus; - message -> last_ = (getTimestamp()).tv_sec; - - message -> locks_ = 0; - - #ifdef DEBUG - *logofs << name() << ": Set last hit of object at " - << strMsTimestamp() << " with a bonus of " - << message -> hits_ << ".\n" << logofs_flush; - #endif - - return position; -} - -// -// The following functions don't modify data, -// so they are supposed to be called only at -// the encoding side. -// - -void MessageStore::updateData(const int position, unsigned int dataSize, - unsigned int compressedDataSize) -{ - Message *message = (*messages_)[position]; - - validateSize(dataSize, compressedDataSize); - - if (compressedDataSize != 0) - { - unsigned int localSize; - unsigned int remoteSize; - - storageSize(message, localSize, remoteSize); - - localStorageSize_ -= localSize; - remoteStorageSize_ -= remoteSize; - - totalLocalStorageSize_ -= localSize; - totalRemoteStorageSize_ -= remoteSize; - - message -> c_size_ = compressedDataSize + message -> i_size_; - - #ifdef TEST - - if (message -> size_ != (int) (dataSize + message -> i_size_)) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Size of object looks " - << message -> size_ << " bytes while it " - << "should be " << dataSize + message -> i_size_ - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Size of object looks " - << message -> size_ << " bytes while it " - << "should be " << dataSize + message -> i_size_ - << ".\n"; - - HandleAbort(); - } - - #endif - - storageSize(message, localSize, remoteSize); - - localStorageSize_ += localSize; - remoteStorageSize_ += remoteSize; - - totalLocalStorageSize_ += localSize; - totalRemoteStorageSize_ += remoteSize; - - #ifdef DEBUG - - printStorageSize(); - - #endif - } -} - -void MessageStore::updateData(const T_checksum checksum, unsigned int compressedDataSize) -{ - #ifdef TEST - *logofs << name() << ": Searching checksum [" - << DumpChecksum(checksum) << "] in repository.\n" - << logofs_flush; - #endif - - T_checksums::iterator found = checksums_ -> find(checksum); - - if (found != checksums_ -> end()) - { - Message *message = (*messages_)[found -> second]; - - #ifdef TEST - *logofs << name() << ": Message found in cache at " - << "position " << found -> second << " with size " - << message -> size_ << " and compressed size " - << message -> c_size_ << ".\n" << logofs_flush; - #endif - - updateData(found -> second, message -> size_ - - message -> i_size_, compressedDataSize); - } - #ifdef TEST - else if (checksums_ -> size() > 0) - { - *logofs << name() << ": WARNING! Can't locate the " - << "checksum [" << DumpChecksum(checksum) - << "] for the update.\n" << logofs_flush; - } - #endif -} - -// -// This function replaces the data part of the message -// and updates the information about its size. Split -// messages are advertised to the decoding side with -// their uncompressed size, data is then compressed -// before sending the first chunk. This function is -// called by the decoding side after the split message -// is fully recomposed to replace the dummy data and -// set the real size. -// - -void MessageStore::updateData(const int position, const unsigned char *newData, - unsigned int dataSize, unsigned int compressedDataSize) -{ - Message *message = (*messages_)[position]; - - validateSize(dataSize, compressedDataSize); - - #ifdef TEST - - if (message -> size_ != (int) (dataSize + message -> i_size_)) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Data of object looks " - << dataSize << " bytes while it " << "should be " - << message -> size_ - message -> i_size_ - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Data of object looks " - << dataSize << " bytes while it " << "should be " - << message -> size_ - message -> i_size_ - << ".\n"; - - HandleAbort(); - } - - #endif - - // - // A compressed data size of 0 means that - // message's data was not compressed. - // - - if (compressedDataSize != 0) - { - unsigned int localSize; - unsigned int remoteSize; - - storageSize(message, localSize, remoteSize); - - localStorageSize_ -= localSize; - remoteStorageSize_ -= remoteSize; - - totalLocalStorageSize_ -= localSize; - totalRemoteStorageSize_ -= remoteSize; - - if (message -> c_size_ != (int) compressedDataSize + - message -> i_size_) - { - #ifdef TEST - *logofs << name() << ": Resizing data of message at " - << "position " << position << " from " << message -> - c_size_ << " to " << compressedDataSize + - message -> i_size_ << " bytes.\n" - << logofs_flush; - #endif - - message -> data_.clear(); - - message -> data_.resize(compressedDataSize); - } - - memcpy(message -> data_.begin(), newData, compressedDataSize); - - #ifdef TEST - *logofs << name() << ": Data of message at position " - << position << " has size " << message -> data_.size() - << " and capacity " << message -> data_.capacity() - << ".\n" << logofs_flush; - #endif - - message -> c_size_ = compressedDataSize + message -> i_size_; - - storageSize(message, localSize, remoteSize); - - localStorageSize_ += localSize; - remoteStorageSize_ += remoteSize; - - totalLocalStorageSize_ += localSize; - totalRemoteStorageSize_ += remoteSize; - - #ifdef DEBUG - - printStorageSize(); - - #endif - } - else - { - #ifdef TEST - *logofs << name() << ": No changes to data size for message " - << "at position " << position << ".\n" << logofs_flush; - #endif - - memcpy(message -> data_.begin(), newData, dataSize); - } -} - -int MessageStore::remove(const int position, T_checksum_action checksumAction, - T_data_action dataAction) -{ - Message *message; - - if (position < 0 || position >= cacheSlots || - (message = (*messages_)[position]) == NULL) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Cannot remove " - << "a non existing message at position " - << position << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot remove " - << "a non existing message at position " - << position << ".\n"; - - HandleAbort(); - } - - #if defined(TEST) || defined(INFO) - - if (opcode() == X_PutImage || opcode() == X_NXPutPackedImage) - { - #ifdef WARNING - *logofs << name() << ": WARNING! Discarding image object " - << "of type " << name() << " at position " - << position << ".\n" << logofs_flush; - #endif - } - - #endif - - // - // The checksum is only stored at the encoding - // side. - // - - if (checksumAction == use_checksum) - { - #ifdef DEBUG - *logofs << name() << ": Removing checksum for object at " - << "position " << position << ".\n" << logofs_flush; - #endif - - // - // TODO: If we had stored the iterator and - // not the pointer to the message, we could - // have removed the message without having - // to look up the checksum. - // - - T_checksum checksum = getChecksum(message); - - #ifdef TEST - *logofs << name() << ": Searching checksum [" - << DumpChecksum(checksum) << "] in repository.\n" - << logofs_flush; - #endif - - T_checksums::iterator found = checksums_ -> find(checksum); - - if (found == checksums_ -> end()) - { - #ifdef PANIC - *logofs << name() << ": PANIC! No checksum found for " - << "object at position " << position << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": No checksum found for " - << "object at position " << position << ".\n"; - - HandleAbort(); - } - - #ifdef TEST - - else if (position != found -> second) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Value of position for object " - << "doesn't match position " << position << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Value of position for object " - << "doesn't match position " << position << ".\n"; - - HandleAbort(); - } - - #endif - - checksums_ -> erase(found); - } - - #ifdef DEBUG - *logofs << name() << ": Removing message at position " - << position << " of size " << plainSize(position) - << " (" << message -> size_ << "/" << message -> c_size_ - << ").\n" << logofs_flush; - #endif - - unsigned int localSize; - unsigned int remoteSize; - - storageSize(message, localSize, remoteSize); - - localStorageSize_ -= localSize; - remoteStorageSize_ -= remoteSize; - - totalLocalStorageSize_ -= localSize; - totalRemoteStorageSize_ -= remoteSize; - - recycle(message); - - (*messages_)[position] = NULL; - - #ifdef DEBUG - - printStorageSize(); - - #endif - - return position; -} - -// -// This should only be called at encoding side. -// The decoding side can't rely on the counter -// as it is decremented by the encoding side -// every time the repository is searched for a -// message to be removed. -// - -int MessageStore::getRating(Message *message, T_rating type) const -{ - if (message -> locks_ != 0) - { - #ifdef TEST - *logofs << name() << ": Rate set to -1 as locks of object are " - << (int) message -> locks_ << ".\n" - << logofs_flush; - #endif - - return -1; - } - else if ((type == rating_for_clean || - (int) checksums_ -> size() == cacheSlots) && - message -> hits_ <= control -> StoreHitsLoadBonus) - { - // - // We don't have any free slot or we exceeded the - // available storage size. This is likely to happen - // after having loaded objects from persistent cache. - // It's not a bad idea to discard some messages that - // were restored but never referenced. - // - - #ifdef TEST - - if (type == rating_for_clean) - { - *logofs << name() << ": Rate set to 0 with hits " - << message -> hits_ << " as maximum storage size " - << "was exceeded.\n" << logofs_flush; - } - else - { - *logofs << name() << ": Rate set to 0 with hits " - << message -> hits_ << " as there are no available " - << "slots in store.\n" << logofs_flush; - } - - #endif - - return 0; - } - else if (type == rating_for_clean && - (getTimestamp()).tv_sec - message -> last_ >= - control -> StoreTimeLimit) - { - #ifdef TEST - *logofs << name() << ": Rate set to 0 as last hit of object was " - << (getTimestamp()).tv_sec - message -> last_ - << " seconds ago with limit set to " << control -> - StoreTimeLimit << ".\n" << logofs_flush; - #endif - - return 0; - } - else - { - #ifdef TEST - if (message -> hits_ < 0) - { - *logofs << name() << ": PANIC! Rate of object shouldn't be " - << message -> hits_ << ".\n" << logofs_flush; - - cerr << "Error" << ": Rate of object of type " << name() - << " shouldn't be " << message -> hits_ << ".\n"; - - HandleAbort(); - } - #endif - - #ifdef TEST - *logofs << name() << ": Rate of object is " << message -> hits_ - << " with last hit " << (getTimestamp()).tv_sec - - message -> last_ << " seconds ago.\n" - << logofs_flush; - #endif - - return message -> hits_; - } -} - -int MessageStore::touch(Message *message) const -{ - message -> last_ = (getTimestamp()).tv_sec; - - message -> hits_ += control -> StoreHitsTouch; - - if (message -> hits_ > control -> StoreHitsLimit) - { - message -> hits_ = control -> StoreHitsLimit; - } - - #ifdef TEST - *logofs << name() << ": Increased hits of object to " - << message -> hits_ << " at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - return message -> hits_; -} - -int MessageStore::untouch(Message *message) const -{ - message -> hits_ -= control -> StoreHitsUntouch; - - if (message -> hits_ < 0) - { - message -> hits_ = 0; - } - - #ifdef TEST - *logofs << name() << ": Decreased hits of object to " - << message -> hits_ << ".\n" - << logofs_flush; - #endif - - return message -> hits_; -} - -int MessageStore::lock(const int position) const -{ - Message *message = (*messages_)[position]; - - if (message == NULL) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Can't lock the null " - << "object at position " << position - << ".\n" << logofs_flush; - #endif - - return -1; - } - - #ifdef DEBUG - *logofs << name() << ": Increasing locks of object to " - << (int) message -> locks_ + 1 << ".\n" - << logofs_flush; - #endif - - return ++(message -> locks_); -} - -int MessageStore::unlock(const int position) const -{ - Message *message = (*messages_)[position]; - - if (message == NULL) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Can't unlock the null " - << "object at position " << position - << ".\n" << logofs_flush; - #endif - - return -1; - } - - #ifdef DEBUG - *logofs << name() << ": Decreasing locks of object to " - << (int) message -> locks_ - 1 << ".\n" - << logofs_flush; - #endif - - return --(message -> locks_); -} - -int MessageStore::saveStore(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient, T_checksum_action checksumAction, - T_data_action dataAction, int bigEndian) -{ - Message *message; - - #ifdef TEST - *logofs << name() << ": Opcode of this store is " - << (unsigned int) opcode() << " default size of " - << "identity is " << dataOffset << ".\n" - << logofs_flush; - #endif - - unsigned char *identityBuffer = new unsigned char[dataOffset]; - unsigned char *sizeBuffer = new unsigned char[4 * 2]; - unsigned char *positionBuffer = new unsigned char[4]; - unsigned char *opcodeBuffer = new unsigned char[4]; - - #ifdef DUMP - - char *md5ClientDump = new char[dataOffset * 2 + 128]; - - #endif - - unsigned char value; - - int offset; - - int failed = 0; - - for (int position = 0; position < cacheSlots; position++) - { - message = (*messages_)[position]; - - // - // Don't save split messages. - // - - if (message != NULL && message -> locks_ == 0) - { - // - // Use the total size if offset is - // beyond the real end of message. - // - - offset = dataOffset; - - if (offset > message -> size_) - { - offset = message -> size_; - } - - #ifdef TEST - *logofs << name() << ": Going to save message at position " - << position << ".\n" << logofs_flush; - #endif - - value = 1; - - PutULONG(position, positionBuffer, bigEndian); - PutULONG(opcode(), opcodeBuffer, bigEndian); - - md5_append(md5StateClient, positionBuffer, 4); - md5_append(md5StateClient, opcodeBuffer, 4); - - #ifdef DUMP - - *logofs << "Name=" << name() << logofs_flush; - - sprintf(md5ClientDump," Pos=%d Op=%d\n", position, opcode()); - - *logofs << md5ClientDump << logofs_flush; - - #endif - - if (PutData(cachefs, &value, 1) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure writing " << 1 - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, &value, 1); - - PutULONG(message -> size_, sizeBuffer, bigEndian); - PutULONG(message -> c_size_, sizeBuffer + 4, bigEndian); - - // - // Note that the identity size is not saved with - // the message and will be determined from the - // data read when restoring the identity. - // - - if (PutData(cachefs, sizeBuffer, 4 * 2) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure writing " << 4 * 2 - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, sizeBuffer, 4 * 2); - md5_append(md5StateClient, sizeBuffer, 4 * 2); - - #ifdef DUMP - - sprintf(md5ClientDump, "size = %d c_size = %d\n", - message -> size_, message -> c_size_); - - *logofs << md5ClientDump << logofs_flush; - - #endif - - // - // Prepare a clean buffer for unparse. - // - - CleanData(identityBuffer, offset); - - unparseIdentity(message, identityBuffer, offset, bigEndian); - - if (PutData(cachefs, identityBuffer, offset) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure writing " << offset - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, identityBuffer, offset); - md5_append(md5StateClient, identityBuffer, offset); - - #ifdef DUMP - - for (int i = 0; i < offset; i++) - { - sprintf(md5ClientDump + (i * 2), "%02X", identityBuffer[i]); - } - - *logofs << "Identity = " << md5ClientDump << "\n" << logofs_flush; - - #endif - - // - // Set the real identity size before - // saving the data. - // - - offset = message -> i_size_; - - if (offset > message -> size_) - { - offset = message -> size_; - } - - if (checksumAction == use_checksum) - { - if (PutData(cachefs, message -> md5_digest_, MD5_LENGTH) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure writing " << MD5_LENGTH - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, message -> md5_digest_, MD5_LENGTH); - } - else if (dataAction == use_data) - { - int dataSize = (message -> c_size_ == 0 ? - message -> size_ - offset : - message -> c_size_ - offset); - if (dataSize > 0) - { - if (PutData(cachefs, message -> data_.begin(), dataSize) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure writing " << dataSize - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, message -> data_.begin(), dataSize); - } - } - } - else - { - #ifdef TEST - *logofs << name() << ": Not saving message at position " - << position << ".\n" << logofs_flush; - #endif - - value = 0; - - if (PutData(cachefs, &value, 1) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure writing " << 1 - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, &value, 1); - } - } - - if (failed == 1) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Write to persistent cache file failed.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Write to persistent cache file failed.\n"; - } - - delete [] identityBuffer; - delete [] sizeBuffer; - delete [] positionBuffer; - delete [] opcodeBuffer; - - #ifdef DUMP - - delete [] md5ClientDump; - - #endif - - return (failed == 0 ? 1 : -1); -} - -int MessageStore::loadStore(istream *cachefs, md5_state_t *md5StateStream, - T_checksum_action checksumAction, T_data_action dataAction, - int bigEndian) -{ - Message *message; - - #ifdef TEST - *logofs << name() << ": Opcode of this store is " - << (unsigned int) opcode() << " default size of " - << "identity is " << dataOffset << " slots are " - << cacheSlots << ".\n" << logofs_flush; - #endif - - // - // If packed images or the render extension has been - // disabled we don't need to restore these messages - // in the cache. Encoding of RENDER in 1.4.0 is also - // changed so we want to skip messages saved using - // the old format. We want to restore all the other - // messages so we'll need to skip these one by one. - // - - int skip = 0; - - if ((opcode() == X_NXPutPackedImage && - control -> PersistentCacheLoadPacked == 0) || - (opcode() == X_NXInternalRenderExtension && - control -> PersistentCacheLoadRender == 0)) - { - #ifdef TEST - *logofs << name() << ": All messages for OPCODE#" - << (unsigned int) opcode() << " will be discarded.\n" - << logofs_flush; - #endif - - skip = 1; - } - - unsigned char *identityBuffer = new unsigned char[dataOffset]; - unsigned char *sizeBuffer = new unsigned char[4 * 2]; - - unsigned char value; - - int offset; - - int failed = 0; - - for (int position = 0; position < cacheSlots; position++) - { - if (GetData(cachefs, &value, 1) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure reading " << 1 - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, &value, 1); - - if (value == 1) - { - #ifdef TEST - *logofs << name() << ": Going to load message at position " - << position << ".\n" << logofs_flush; - #endif - - if (GetData(cachefs, sizeBuffer, 4 * 2) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure reading " << 4 * 2 - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, sizeBuffer, 4 * 2); - - message = getTemporary(); - - if (message == NULL) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Can't access temporary storage " - << "for message in context [B].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't access temporary storage " - << "for message in context [B].\n"; - - failed = 1; - - break; - } - - message -> size_ = GetULONG(sizeBuffer, bigEndian); - message -> c_size_ = GetULONG(sizeBuffer + 4, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Size is " << message -> size_ - << " compressed size is " << message -> c_size_ - << ".\n" << logofs_flush; - #endif - - // - // Use the total size if offset is - // beyond the real end of message. - // - - offset = dataOffset; - - if (offset > message -> size_) - { - offset = message -> size_; - } - - if (GetData(cachefs, identityBuffer, offset) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure reading " << offset - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, identityBuffer, offset); - - // - // Get the real identity size based on the value - // reported by the message store. The dataOffset - // value is guaranteed to be greater or equal to - // the maximum identity size of the messages in - // the major store. - // - - offset = identitySize(identityBuffer, offset); - - if (offset > message -> size_) - { - offset = message -> size_; - } - - message -> i_size_ = offset; - - // - // Get identity of message from the buffer we just - // created. Don't calculate neither checksum nor - // data, restore them from stream. Don't pass the - // message's size but the default size of identity. - // - - parseIdentity(message, identityBuffer, offset, bigEndian); - - if (checksumAction == use_checksum) - { - if (message -> md5_digest_ == NULL) - { - message -> md5_digest_ = new md5_byte_t[MD5_LENGTH]; - } - - if (GetData(cachefs, message -> md5_digest_, MD5_LENGTH) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure reading " << MD5_LENGTH - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - // - // Add message's checksum to checksum that will - // be saved together with this cache. Checksum - // will be verified when cache file is restored - // to ensure file is not corrupted. - // - - md5_append(md5StateStream, message -> md5_digest_, MD5_LENGTH); - - if (skip == 1) - { - #ifdef TEST - *logofs << name() << ": Discarding message for OPCODE#" - << (unsigned int) opcode() << ".\n" - << logofs_flush; - #endif - - continue; - } - } - else if (dataAction == use_data) - { - // - // Restore the data part. - // - - int dataSize = (message -> c_size_ == 0 ? - message -> size_ - offset : - message -> c_size_ - offset); - - if (dataSize < 0 || dataSize > control -> MaximumMessageSize) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Bad data size " - << dataSize << " loading persistent cache.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Bad data size " << dataSize - << " loading persistent cache.\n"; - - failed = 1; - - break; - } - else if (dataSize > 0) - { - // - // If need to skip the message let anyway - // it to be part of the calculated MD5. - // - - if (skip == 1) - { - unsigned char *dummy = new unsigned char[dataSize]; - - if (dummy == NULL) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Can't allocate dummy buffer " - << "of size " << dataSize << " loading cache.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate dummy buffer " - << "of size " << dataSize << " loading cache.\n"; - - failed = 1; - - break; - } - - if (GetData(cachefs, dummy, dataSize) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure reading " << dataSize - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - md5_append(md5StateStream, dummy, dataSize); - - delete [] dummy; - - #ifdef TEST - *logofs << name() << ": Discarding message for OPCODE#" - << (unsigned int) opcode() << ".\n" - << logofs_flush; - #endif - - continue; - } - else - { - message -> data_.clear(); - - message -> data_.resize(dataSize); - - if (GetData(cachefs, message -> data_.begin(), dataSize) < 0) - { - #ifdef DEBUG - *logofs << name() << ": PANIC! Failure reading " << dataSize - << " bytes.\n" << logofs_flush; - #endif - - failed = 1; - - break; - } - - // - // Add message's data to cache checksum. - // - - md5_append(md5StateStream, message -> data_.begin(), dataSize); - } - } - else - { - // - // We are here if data part is zero. - // - - if (skip == 1) - { - #ifdef TEST - *logofs << name() << ": Discarding message for OPCODE#" - << (unsigned int) opcode() << ".\n" - << logofs_flush; - #endif - - continue; - } - } - } - - int added; - - added = add(message, position, checksumAction, dataAction); - - if (added != position) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Can't store message " - << "in the cache at position " << position - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't store message " - << "in the cache at position " << position - << ".\n"; - - failed = 1; - - break; - } - else - { - // - // Replace default value of hits set by add - // function. Messages read from cache start - // with a lower bonus than fresh messages - // inserted. - // - - message -> hits_ = control -> StoreHitsLoadBonus; - - #ifdef DEBUG - *logofs << name() << ": Updated last hit of object at " - << strMsTimestamp() << " with a bonus of " - << message -> hits_ << ".\n" << logofs_flush; - #endif - - resetTemporary(); - } - } - else if ((*messages_)[position] != NULL) - { - #ifdef TEST - *logofs << name() << ": Going to remove message at position " - << position << ".\n" << logofs_flush; - #endif - - int removed; - - removed = remove(position, checksumAction, dataAction); - - if (removed != position) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Can't remove message from cache " - << "at position " << position << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't remove message from cache " - << "at position " << position << ".\n"; - - failed = 1; - - break; - } - } - #ifdef TEST - else - { - *logofs << name() << ": Not loading message at position " - << position << ".\n" << logofs_flush; - } - #endif - } - - #ifdef WARNING - - if (failed == 1) - { - *logofs << name() << ": WARNING! Read from persistent cache file failed.\n" - << logofs_flush; - } - - #endif - - delete [] identityBuffer; - delete [] sizeBuffer; - - return (failed == 0 ? 1 : -1); -} - -void MessageStore::storageSize(const Message *message, unsigned int &local, - unsigned int &remote) const -{ - local = remote = storage(); - - // - // Encoding side includes 48 bytes for - // the map of checksums and 24 bytes - // of adjustment for total overhead. - // - - local += MD5_LENGTH + 48 + 24; - - // - // At decoding side we include size of - // data part and 24 bytes of adjustment - // for total overhead. - // - - if (message -> c_size_ == 0) - { - remote += message -> size_ + 24; - } - else - { - remote += message -> c_size_ + 24; - } - - // - // Check if we are the encoding or the - // decoding side and, if needed, swap - // the values. - // - - if (message -> md5_digest_ == NULL) - { - unsigned int t = local; - - local = remote; - - remote = t; - } -} - -void MessageStore::printStorageSize() -{ - #ifdef TEST - - *logofs << name() << ": There are " - << checksums_ -> size() << " checksums in this store " - << "out of " << cacheSlots << " slots.\n" - << logofs_flush; - - *logofs << name() << ": Size of this store is " - << localStorageSize_ << " bytes at local side and " - << remoteStorageSize_ << " bytes at remote side.\n" - << logofs_flush; - - *logofs << name() << ": Size of total cache is " - << totalLocalStorageSize_ << " bytes at local side and " - << totalRemoteStorageSize_ << " bytes at remote side.\n" - << logofs_flush; - - #endif -} diff --git a/nxcomp/Message.h b/nxcomp/Message.h deleted file mode 100644 index 30883f101..000000000 --- a/nxcomp/Message.h +++ /dev/null @@ -1,1089 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Message_H -#define Message_H - -#include - -#include "NXproto.h" - -#include "Misc.h" -#include "Control.h" - -#include "Types.h" -#include "Timestamp.h" - -#include "ActionCache.h" - -#include "StaticCompressor.h" - -// -// Forward class declarations. -// - -class ChannelCache; - -class EncodeBuffer; -class DecodeBuffer; - -class WriteBuffer; - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Define this to know how many messages -// are allocated and deallocated. -// - -#undef REFERENCES - -// -// Set default values. We limit the maximum -// size of a request to 262144 but we need to -// consider the replies, whose size may be up -// to 4MB. -// - -#define MESSAGE_ENABLE_CACHE 0 -#define MESSAGE_ENABLE_DATA 0 -#define MESSAGE_ENABLE_SPLIT 0 -#define MESSAGE_ENABLE_COMPRESS 0 - -#define MESSAGE_DATA_LIMIT 4194304 - 4 -#define MESSAGE_DATA_OFFSET 4 - -#define MESSAGE_CACHE_SLOTS 6000 -#define MESSAGE_CACHE_THRESHOLD 50 -#define MESSAGE_CACHE_LOWER_THRESHOLD 5 - -// -// Base message class. -// - -class Message -{ - friend class MessageStore; - friend class RenderExtensionStore; - - public: - - Message() - { - hits_ = 0; - last_ = 0; - locks_ = 0; - - size_ = 0; - c_size_ = 0; - - md5_digest_ = NULL; - - #ifdef REFERENCES - - references_++; - - *logofs << "Message: Created new message at " - << this << " out of " << references_ - << " allocated messages.\n" - << logofs_flush; - - #endif - } - - Message(const Message &message) - { - size_ = message.size_; - c_size_ = message.c_size_; - i_size_ = message.i_size_; - - hits_ = message.hits_; - last_ = message.last_; - locks_ = message.locks_; - - data_ = message.data_; - - #ifdef REFERENCES - - references_++; - - *logofs << "Message: Creating new copied message at " - << this << " out of " << references_ - << " allocated messages.\n" - << logofs_flush; - #endif - - if (message.md5_digest_ != NULL) - { - md5_digest_ = new md5_byte_t[MD5_LENGTH]; - - memcpy(md5_digest_, message.md5_digest_, MD5_LENGTH); - - #ifdef DEBUG - *logofs << "Message: Created MD5 digest for object at " - << this << ".\n" << logofs_flush; - #endif - } - else - { - md5_digest_ = NULL; - } - } - - ~Message() - { - #ifdef DEBUG - if (md5_digest_ != NULL) - { - *logofs << "Message: Deleted MD5 digest for object at " - << this << ".\n" << logofs_flush; - } - #endif - - delete [] md5_digest_; - - #ifdef REFERENCES - - references_--; - - *logofs << "Message: Deleted message at " - << this << " out of " << references_ - << " allocated messages.\n" - << logofs_flush; - #endif - } - - // - // This is the original message size - // including the data part regardless - // data is still stored in the object. - // - - int size_; - - // - // This is the size of the identity. - // - - int i_size_; - - // - // This is the size, including identity, - // after message has been 'updated' to - // reflect storage of data in compressed - // format. - // - - int c_size_; - - protected: - - // - // This is the data part. - // - - T_data data_; - - // - // Time of last hit. - // - - time_t last_; - - // - // This is the number of cache hits - // registered for the object. - // - - short int hits_; - - // - // This is used to mark messages - // that have been split. - // - - short int locks_; - - // - // This is the MD5 checksum. - // - - md5_byte_t *md5_digest_; - - // - // Keep a reference counter - // of allocated objects. - // - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -// -// Repository of messages. -// - -class MessageStore -{ - public: - - // - // Enable or disable cache of messages in store. - // - - int enableCache; - - // - // Does message have a distinct data part. - // - - int enableData; - - // - // Enable or disable split of data part. - // - - int enableSplit; - - // - // Enable or disable compression of data part. - // - - int enableCompress; - - // - // Set starting point of data part in the message. - // - - int dataOffset; - - // - // Set maximum size for the data part of each message. - // - - int dataLimit; - - // - // Set maximum elements in cache. - // - - int cacheSlots; - - // - // Set the percentage of total cache memory which - // a given type of message is allowed to occupy. - // When threshold is exceeded store is cleaned to - // make room for a new message of the same type. - // - - int cacheThreshold; - - // - // Don't clean the store if percentage of cache - // memory occupied by messages of this type is - // below the threshold. - // - - int cacheLowerThreshold; - - // - // Last operation performed on cache. - // - - T_store_action lastAction; - - // - // Position of last element stored in cache. - // - - short int lastAdded; - - // - // Positions of last element found in cache. - // - - short int lastHit; - - // - // Position of last element erased. - // - - short int lastRemoved; - - // - // Used to encode the the action to - // perform on the store and the slot - // involved. - // - - ActionCache lastActionCache; - - // - // Position in cache where next insertion - // is going to take place. - // - - short int lastRated; - - // - // Constructors and destructors. - // - - public: - - MessageStore(StaticCompressor *compressor = NULL); - - virtual ~MessageStore(); - - virtual const char *name() const = 0; - - virtual unsigned char opcode() const = 0; - - virtual unsigned int storage() const = 0; - - // - // These are members that must be specialized. - // - - public: - - virtual Message *create() const = 0; - - virtual Message *create(const Message &message) const = 0; - - virtual void destroy(Message *message) const = 0; - - void validateSize(int size) - { - if (size < control -> MinimumMessageSize || - size > control -> MaximumMessageSize) - { - *logofs << name() << ": PANIC! Invalid size " << size - << " for message.\n" << logofs_flush; - - cerr << "Error" << ": Invalid size " << size - << " for message opcode " << opcode() << ".\n"; - - HandleAbort(); - } - } - - void validateSize(int dataSize, int compressedDataSize) - { - if (dataSize < 0 || dataSize > control -> - MaximumMessageSize - 4 || compressedDataSize < 0 || - compressedDataSize >= dataSize) - { - *logofs << name() << ": PANIC! Invalid data size " - << dataSize << " and compressed data size " - << compressedDataSize << " for message.\n" - << logofs_flush; - - cerr << "Error" << ": Invalid data size " - << dataSize << " and compressed data size " - << compressedDataSize << " for message " - << "opcode " << (unsigned) opcode() << ".\n"; - - HandleAbort(); - } - } - - // - // Determine if the message can be stored - // in the cache. - // - - virtual int validateMessage(const unsigned char *buffer, int size) - { - return (size >= control -> MinimumMessageSize && - size <= control -> MaximumMessageSize); - } - - // - // Get data offset based on major and minor - // opcode of the message. - // - - virtual int identitySize(const unsigned char *buffer, unsigned int size) - { - return dataOffset; - } - - // - // Encode identity and data using the - // specific message encoding. - // - // Some messages do not implement these - // methods because the encoding is done - // directly in the channel loop. Should - // move the encoding methods in in the - // message classes. - // - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int size, int bigEndian, - ChannelCache *channelCache) const - { - return 1; - } - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const - { - return 1; - } - - // - // Encode differences between message - // in cache and the one to be encoded. - // - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, ChannelCache *channelCache) const - { - } - - // - // Decode differences and update the - // cached version of the same message. - // - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const - { - } - - // - // Post process the message information - // contained in the store by either up- - // dating the size record or the actual - // data part once the message has been - // completely sent to our peer. - // - - void updateData(const int position, unsigned int dataSize, - unsigned int compressedDataSize); - - void updateData(const T_checksum checksum, unsigned int compressedDataSize); - - void updateData(const int position, const unsigned char *newData, - unsigned int dataSize, unsigned int compressedDataSize); - - // - // These members, used internally - // in the message store class, are - // mandatory. - // - - protected: - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const = 0; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const = 0; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const = 0; - - virtual void dumpIdentity(const Message *message) const = 0; - - // - // Design should preserve these from being - // virtual. - // - - int parseData(Message *message, int split, const unsigned char *buffer, - unsigned int size, T_checksum_action checksumAction, - T_data_action dataAction, int bigEndian); - - int parseData(Message *message, const unsigned char *buffer, - unsigned int size, const unsigned char *compressedData, - const unsigned int compressedDataSize, T_checksum_action checksumAction, - T_data_action dataAction, int bigEndian); - - int unparseData(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian); - - // - // Manage efficient allocation of messages - // in the heap. - // - - void recycle(Message *message) - { - #ifdef TEST - - if (message == NULL) - { - *logofs << name() << ": PANIC! Cannot recycle a null message.\n" - << logofs_flush; - - cerr << "Error" << ": Cannot recycle a null message.\n"; - - HandleAbort(); - } - - #endif - - if (temporary_ == NULL) - { - // - // Be careful when reusing the message as - // it can contain valid data that must be - // explicitly deallocated if not needed. - // Note also that you cannot count on the - // initialization made in costructor. - // - - temporary_ = message; - } - else - { - destroy(message); - } - } - - void beginChecksum(Message *message) - { - if (message -> md5_digest_ == NULL) - { - message -> md5_digest_ = new md5_byte_t[MD5_LENGTH]; - - #ifdef DEBUG - *logofs << name() << ": Created MD5 digest structure " - << "for object at " << message << ".\n" - << logofs_flush; - #endif - } - #ifdef DEBUG - else - { - *logofs << name() << ": Using existing MD5 digest structure " - << "for object at " << message << ".\n" - << logofs_flush; - } - #endif - - #ifdef DEBUG - *logofs << name() << ": Prepared MD5 digest for object at " - << message << ".\n" << logofs_flush; - #endif - - md5_init(md5_state_); - } - - void endChecksum(Message *message) - { - md5_finish(md5_state_, message -> md5_digest_); - - #ifdef DEBUG - *logofs << name() << ": Calculated checksum for object at " - << message << ".\n" << logofs_flush; - #endif - } - - void dataChecksum(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) - { - // - // Messages that have a data part starting - // at an offset possibly beyond the end of - // the message, must include the size in - // the identity checksum. - // - - if ((int) size > message -> i_size_) - { - md5_append(md5_state_, buffer + message -> i_size_, - size - message -> i_size_); - } - } - - // - // Repository handling methods. - // - - public: - - // - // Extract identity and data from buffer. - // The size field will be updated at the - // time of data parsing. - // - - int parse(Message *message, int split, const unsigned char *buffer, unsigned int size, - T_checksum_action checksumAction, T_data_action dataAction, int bigEndian); - - int parse(Message *message, const unsigned char *buffer, unsigned int size, - const unsigned char *compressedData, const unsigned int compressedDataSize, - T_checksum_action checksumAction, T_data_action dataAction, int bigEndian); - - // - // From identity and data write the - // final message to the raw buffer. - // - - int unparse(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) - { - return (unparseData(message, buffer, size, bigEndian) && - unparseIdentity(message, buffer, size, bigEndian)); - } - - void dump(const Message *message) const - { - dumpIdentity(message); - - dumpData(message); - } - - void dumpData(const Message *message) const; - - // - // This returns the original message size as it - // was received on the link. It takes in account - // the data part, regardless data is still stored - // in the message object. This information will - // be used at the time message is unparsed. - // - - int plainSize(const int position) const - { - return (*messages_)[position] -> size_; - } - - // - // This returns either the size of identity plus - // the compressed data part or 0 if message is - // stored in uncompressed format. - // - - int compressedSize(const int position) const - { - return (*messages_)[position] -> c_size_; - } - - // - // Returns a pointer to message - // given its position in cache. - // - - Message *get(const int position) const - { - if (position < 0 || position >= cacheSlots) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Requested position " - << position << " is not inside the " - << "container.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Requested position " - << position << " is not inside the" - << "container.\n"; - - HandleAbort(); - } - else if ((*messages_)[position] == NULL) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Message at position " - << position << " is NULL.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Message at position " - << position << " is NULL.\n"; - - HandleAbort(); - } - - return (*messages_)[position]; - } - - // - // This is the method called at encoding - // side to add a message to cache. - // - - int findOrAdd(Message *message, T_checksum_action checksumAction, - T_data_action dataAction, int &added, int &locked); - - // - // Utility interfaces to message insertion - // and deletion. - // - - int add(Message *message, const int position, - T_checksum_action checksumAction, T_data_action dataAction); - - int remove(const int position, T_checksum_action checksumAction, - T_data_action dataAction); - - // - // Make space in the repository by remove - // the first suitable message object. - // - - int clean(T_checksum_action checksumAction); - - // - // Increase or decrease the "rating" of - // the message object. - // - - int touch(Message *message) const; - int untouch(Message *message) const; - - int getTouches(const int position) const - { - Message *message = (*messages_)[position]; - - if (message == NULL) - { - return 0; - } - - return message -> hits_; - } - - // - // Gives a 'weight' to the cached message. A zero - // value means object can be safely removed. A value - // greater than zero means it is advisable to retain - // the object. A negative result means it is mandato- - // ry to keep object in cache. - // - - int getRating(Message *message, T_rating type) const; - - // - // Increase or decrease locks of message at given - // position. A locked message will not be removed - // from the message store until the lock counter - // is zero. - // - - int lock(const int position) const; - int unlock(const int position) const; - - int getLocks(const int position) const - { - Message *message = (*messages_)[position]; - - if (message == NULL) - { - return 0; - } - - return message -> locks_; - } - - T_checksum const getChecksum(const int position) const - { - return getChecksum(get(position)); - } - - T_checksum const getChecksum(const Message *message) const - { - if (message -> md5_digest_ == NULL) - { - #ifdef PANIC - *logofs << name() << ": PANIC! Checksum not initialized " - << "for object at " << message << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Checksum not initialized " - << "for object at " << message << ".\n"; - - HandleAbort(); - } - - #ifdef DEBUG - *logofs << name() << ": Got checksum for object at " - << message << ".\n" << logofs_flush; - #endif - - return message -> md5_digest_; - } - - // - // Calculate the checksum on the fly based the - // opcode in the buffer. Useful in the case a - // message was not processed or was not stored - // in the cache. The returned checksum must be - // explicitly deallocated by the caller, after - // use. - // - - T_checksum getChecksum(const unsigned char *buffer, - unsigned int size, int bigEndian); - - const unsigned char *getData(const Message *message) const - { - return message -> data_.begin(); - } - - int plainSize(const Message *message) const - { - return message -> size_; - } - - int identitySize(Message *message) - { - return message -> i_size_; - } - - int compressedSize(const Message *message) const - { - return message -> c_size_; - } - - Message *getTemporary() - { - if (temporary_ == NULL) - { - temporary_ = create(); - } - - return temporary_; - } - - void resetTemporary() - { - temporary_ = NULL; - } - - // - // On side where we don't have checksums, we - // count how many messages are in the array. - // This is obviously expensive and should be - // only performed when reporting statistics. - // - - int getSize() const - { - int size = checksums_ -> size(); - - if (size == 0) - { - for (int i = 0; i < cacheSlots; i++) - { - if ((*messages_)[i] != NULL) - { - size++; - } - } - } - - return size; - } - - int getLocalStorageSize() const - { - return localStorageSize_; - } - - int getRemoteStorageSize() const - { - return remoteStorageSize_; - } - - int getLocalTotalStorageSize() const - { - return totalLocalStorageSize_; - } - - int getRemoteTotalStorageSize() const - { - return totalRemoteStorageSize_; - } - - static int getCumulativeTotalStorageSize() - { - return (totalLocalStorageSize_ > totalRemoteStorageSize_ ? - totalLocalStorageSize_ : totalRemoteStorageSize_); - } - - int saveStore(ostream *cachefs, md5_state_t *md5_state_stream, - md5_state_t *md5_state_client, T_checksum_action checksumAction, - T_data_action dataAction, int bigEndian); - - int loadStore(istream *cachefs, md5_state_t *md5_state_stream, - T_checksum_action checksumAction, T_data_action dataAction, - int bigEndian); - - protected: - - // - // Estimate the memory requirements of given - // instance of message. Size includes memory - // allocated from heap to store checksum and - // data. - // - - void storageSize(const Message *message, unsigned int &local, - unsigned int &remote) const; - - // - // Just used for debug. - // - - void printStorageSize(); - - // - // Repositories where to save cached messages. - // First is a vector of pointers, the second - // is a hash table used for fast lookups. - // - - T_messages *messages_; - T_checksums *checksums_; - - // - // A message object to be used as a temporary. - // Reuse the temporary object if possible, if - // not, create a new instance. - // - - Message *temporary_; - - // - // Used to calculate message's checksum. - // - - md5_state_t *md5_state_; - - private: - - // - // Used to compress data payload. - // - - StaticCompressor *compressor_; - - // - // Keep track of how many bytes - // are taken by cache. - // - - int localStorageSize_; - int remoteStorageSize_; - - static int totalLocalStorageSize_; - static int totalRemoteStorageSize_; - - // - // Used to track object allocation and deallocation. - // - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -// -// This is an ancillary class of the message -// store, used to encode extensions based on -// the minor opcode. -// - -class MinorMessageStore -{ - public: - - virtual ~MinorMessageStore() - { - } - - virtual const char *name() const = 0; - - virtual int identitySize(const unsigned char *buffer, unsigned int size) = 0; - - virtual int encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const - { - return 1; - } - - virtual int decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, unsigned char type, int bigEndian, - WriteBuffer *writeBuffer, ChannelCache *channelCache) const - { - return 1; - } - - virtual void encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int size, int bigEndian, - ChannelCache *channelCache) const - { - } - - virtual void decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int size, int bigEndian, - ChannelCache *channelCache) const - { - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const = 0; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const = 0; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const - { - } - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const - { - } - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, md5_state_t *md5_state, - int bigEndian) const = 0; -}; - -#endif /* Message_H */ - diff --git a/nxcomp/Misc.cpp b/nxcomp/Misc.cpp deleted file mode 100644 index 09a0b29d2..000000000 --- a/nxcomp/Misc.cpp +++ /dev/null @@ -1,1930 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include -#include - -#include -#include - -#include "NXproto.h" - -#include "MD5.h" - -#include "Misc.h" -#include "Proxy.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#define OPCODES -#undef TEST -#undef DEBUG - -// -// By default nxproxy binds to all network interfaces, setting -// DEFAULT_LOOPBACK_BIND to 1 enables binding to the loopback -// device only. -// - -const int DEFAULT_LOOPBACK_BIND = 0; - -// -// TCP port offset applied to any NX port specification. -// - -const int DEFAULT_NX_PROXY_PORT_OFFSET = 4000; - -// -// Default TCP port used by client proxy to listen to -// X clients and by server proxy to connect to remote. -// - -const int DEFAULT_NX_PROXY_PORT = 8; - -// -// Default X display number that client proxy imitates. -// - -const int DEFAULT_NX_X_PORT = 8; - -// -// Default ports used for listening for cups, samba, http, -// multimedia and auxiliary X connections. Arbitrary ports -// can be used by passing the service's port at the proxy -// startup. By default ports are determined by adding the -// offset below to the offset of the proxied display. For -// example, if the proxy is impersonating the display :8, -// SMB tunnels can be created by connecting to port 3008. -// -// Considering that the NX server uses to start the first -// session at display offset 1000, we must lower the CUPS -// and SMB ports to avoid interference with normal X ses- -// sions run on the server. -// -// Font server connections are used to let the X server on -// the client connect to a font server on the NX server. -// -// Slave channels can be originated by both sides so we need -// different offsets in the case the user runs both proxies -// on the same host. -// - -const int DEFAULT_NX_CUPS_PORT_OFFSET = 2000; -const int DEFAULT_NX_SMB_PORT_OFFSET = 3000; -const int DEFAULT_NX_MEDIA_PORT_OFFSET = 7000; -const int DEFAULT_NX_AUX_PORT_OFFSET = 8000; -const int DEFAULT_NX_HTTP_PORT_OFFSET = 9000; -const int DEFAULT_NX_FONT_PORT_OFFSET = 10000; - -const int DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET = 11000; -const int DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET = 12000; - -// -// Usage info and copyright. -// - -static const char UsageInfo[] = -"\n\ - Usage: nxproxy [OPTIONS] host:port\n\ -\n\ - -C Specify that nxproxy has to run on the 'X client'\n\ - side, listening for connections and impersonating\n\ - an X server.\n\ -\n\ - -S Specify that nxproxy has to run in 'X server' mode,\n\ - thus forwarding the connections to daemons running\n\ - on the client.\n\ -\n\ - -h Print this message.\n\ -\n\ - -v Print version information.\n\ -\n\ - host:port Put at the end, specifies the host and port of the\n\ - listening proxy.\n\ -\n\ - name=value Set the NX option to the provided value.\n\ -\n\ - Multiple NX options can be specified in the DISPLAY environment\n\ - or on the command line, by using the nx/nx,option=value notation.\n\ -\n\ - Options:\n\ -\n\ - link=s An indication of the link speed that is going to be\n\ - used between the proxies. Usually the compression\n\ - and the other link parameters depend on this setting.\n\ - The value can be either 'modem', 'isdn', 'adsl',\n\ - 'wan', 'lan', 'local' or a bandwidth specification,\n\ - like for example '56k', '1m', '100m', etc.\n\ -\n\ - type=s Type of session, for example 'windows', 'unix-kde'.\n\ - 'unix-application', etc.\n\ -\n\ - display=s Specify the real display where X connections have\n\ - to be forwarded by the proxy running on the client.\n\ -\n\ - listen=n Local port used for accepting the proxy connection.\n\ -\n\ - loopback=b Bind to the loopback device only.\n\ -\n\ - accept=s Name or IP of host that can connect to the proxy.\n\ -\n\ - connect=s Name or IP of host that the proxy will connect to.\n\ -\n\ - port=n Remote port used for the connection.\n\ -\n\ - retry=n Number of connection atempts.\n\ -\n\ - root=s The root directory for the session. Usually is the\n\ - C-* or S-* in the .nx directory in the user's home,\n\ - with '*' being the virtual display.\n\ -\n\ - session=s Name of the session file. The default is the name\n\ - 'session' in the session directory.\n\ -\n\ - errors=s Name of the log file used by the proxy. The default\n\ - is the name 'errors' in the session directory.\n\ -\n\ - stats=s Name of the file where are written the proxy stat-\n\ - istics. The default is a file 'stats' in the session\n\ - directory. The proxy replaces the data in the file\n\ - whenever it receives a SIGUSR1 or SIGUSR2 signal:\n\ -\n\ - SIGUSR1 Gives total statistics, i.e. statistics\n\ - collected since the beginning of the\n\ - session.\n\ -\n\ - SIGUSR2 Gives partial statistics, i.e. statist-\n\ - ics collected since the last time this\n\ - signal was received.\n\ -\n\ - cookie=s Use the provided cookie for authenticating to the\n\ - remote proxy. The same cookie is used as the fake\n\ - value used for the X authorization. The fake cookie\n\ - is replaced on the X server side with the real cookie\n\ - to be used for the display, so that the real cookie\n\ - doesn't have to travel over the net. When not using\n\ - a proxy cookie, any host will be able to connect to\n\ - the proxy. See also the 'accept' parameter.\n\ -\n\ - nodelay=b A boolean indicating if TCP_NODELAY has to be set\n\ - on the proxy link. Old Linux kernels had problems\n\ - with handling TCP_NODELAY on PPP links.\n\ -\n\ - policy=b Let or not the agent decide when it is the best time\n\ - to flush the proxy link. If set to 0, the proxy will\n\ - flush any encoded data immediately. The option has\n\ - only effect on the X client side proxy.\n\ -\n\ - render=b Enable or disable use of the RENDER extension.\n\ -\n\ - taint=b Try to suppress trivial sources of X roundtrips by\n\ - generating the reply on the X client side.\n\ -\n\ - delta=b Enable X differential compression.\n\ -\n\ - data=n Enable or disable the ZLIB data compression. It is\n\ - possible to specify a value between 0 and 9. Usual-\n\ - ly the value is chosen automatically based on the\n\ - requested link setting.\n\ -\n\ - stream=n Enable or disable the ZLIB stream compression. The\n\ - value, between 0 and 9, is usually determined accor-\n\ - ding to the requested link setting.\n\ -\n\ - limit=n Specify a bitrate limit allowed for this session.\n\ -\n\ - memory=n Trigger memory optimizations used to keep small the\n\ - size of X buffers. This is useful on embedded plat-\n\ - forms, or where memory is scarce.\n\ -\n\ - cache=n Size of the in-memory X message cache. Setting the\n\ - value to 0 will disable the memory cache as well\n\ - as the NX differential compression.\n\ -\n\ - images=n Size of the persistent image cache.\n\ -\n\ - shseg=n Enable the use of the MIT-SHM extension between the\n\ - NX client proxy and the real X server. A value greater\n\ - than 1 is assumed to be the size of requested shared\n\ - memory segment. By default, the size of the segment is\n\ - determined based on the size of the in-memory cache.\n\ -\n\ - load=b Enable loading a persistent X message cache at the\n\ - proxy startup.\n\ -\n\ - save=b Enable saving a persistent X message cache at the\n\ - end of session.\n\ -\n\ - cups=n Enable or disable forwarding of CUPS connections,\n\ - by listening on the optional port 'n'.\n\ -\n\ - aux=n Enable or disable forwarding of the auxiliary X chan-\n\ - nel used for controlling the keyboard. The 'keybd=n'\n\ - form is accepted for backward compatibility.\n\ -\n\ - smb=n Enable or disable forwarding of SMB connections. The\n\ - 'samba=n' form is accepted for backward compatibility.\n\ -\n\ - media=n Enable forwarding of audio connections.\n\ -\n\ - http=n Enable forwarding of HTTP connections.\n\ -\n\ - font=n Enable forwarding of reversed connections to a font\n\ - server running on the NX server.\n\ -\n\ - file=n Enable forwarding of file transfer connections.\n\ -\n\ - mask=n Determine the distribution of channel ids between the\n\ - proxies. By default, channels whose ids are multiple\n\ - of 8 (starting from 0) are reserved for the NX client\n\ - side. All the other channels can be allocated by the\n\ - NX server side.\n\ -\n\ - timeout=t Specify the keep-alive timeout used by proxies to\n\ - determine if there is a network problem preventing\n\ - communication with the remote peer. A value of 0\n\ - disables the check.\n\ -\n\ - cleanup=t Specify the number of seconds the proxy has to wait\n\ - at session shutdown before closing all channels.\n\ - The feature is used by the NX server to ensure that\n\ - services are disconnected before shutting down the\n\ - link.\n\ -\n\ - pack=s Determine the method used to compress images.\n\ -\n\ - product=s The product id of the client or server. The value is\n\ - ignored by the proxy, but the client or server can\n\ - provide it to facilitate the support.\n\ -\n\ - core=b Enable production of core dumps when aborting the\n\ - proxy connection.\n\ -\n\ - options=s Specify an additional file containing options that\n\ - has to be merged with option read from the command\n\ - line or the environment.\n\ -\n\ - kill=n Add the given process to the list of daemons that\n\ - must be terminated at session shutdown. Multiple\n\ - 'kill=n' options can be specified. The proxy will\n\ - send them a SIGTERM signal just before exiting.\n\ -\n\ - strict=b Optimize for responsiveness, rather than for the best\n\ - use of all the available bandwidth.\n\ -\n\ - encryption=b Should be set to 1 if the proxy is running as part of\n\ - a program providing encryption of the point to point\n\ - communication.\n\ -\n\ -rootless=b\n\ -geometry=s\n\ -resize=b\n\ -fullscreen=b\n\ -keyboard=s\n\ -clipboard=s\n\ -streaming=n\n\ -backingstore=n\n\ -composite=n\n\ -xinerama=n\n\ -shmem=b\n\ -shpix=b\n\ -kbtype=s\n\ -client=s\n\ -shadow=n\n\ -shadowuid=n\n\ -shadowmode=s\n\ -defer=n\n\ -tile=s\n\ -menu=n\n\ -sleep=n\n\ -tolerancechecks=s\n\ - These options are interpreted by the NX agent. They\n\ - are ignored by the proxy.\n\ -\n\ - Environment:\n\ -\n\ - NX_ROOT The root NX directory is the place where the session\n\ - directory and the cache files are created. This is\n\ - usually overridden by passing the 'root=' option. By\n\ - default, the root NX directory is assumed to be the\n\ - directory '.nx' in the user's home.\n\ -\n\ - NX_SYSTEM The directory where NX programs and libraries reside.\n\ - If not set, the value is assumed to be '/usr/NX'.\n\ - Programs, libraries and data files are respectedly\n\ - searched in the 'bin', 'lib' and 'share' subdirecto-\n\ - ries.\n\ -\n\ - NX_HOME The NX user's home directory. If NX_ROOT is not set\n\ - or invalid, the user's NX directory is created here.\n\ -\n\ - NX_TEMP The directory where the X11 Unix Domain Sockets and\n\ - all temporary files are to be created.\n\ -\n\ - NX_CLIENT The full path to the nxclient executable. If the va-\n\ - riable is not set, the nxclient executable will be\n\ - run assuming that the program is in the system path.\n\ - This can be useful on platforms like Windows and the\n\ - Mac where nxclient is located in a different direct-\n\ - ory compared to the other programs, to make easier\n\ - for the user to execute the program from the shell.\n\ -\n\ - NX_SLAVE_CMD The full path to the slave channel handler. When the\n\ - slave channel is enabled, the agent will listen on a\n\ - port and forward the connection to the NX_SLAVE_CMD\n\ - program. This can be used to implement agent/proxy\n\ - communication for applications such as serial port and\n\ - USB forwarding.\n\ -\n\ - Shell environment:\n\ -\n\ - HOME The variable is checked in the case NX_HOME is not\n\ - set, null or invalid.\n\ -\n\ - TEMP The variable is checked whenever the NX_TEMP direct-\n\ - ory is not set, null or invalid.\n\ -\n\ - PATH The path where all executables are searched, except\n\ - nxclient. If NX_CLIENT is not set, also the client\n\ - executable is searched in the system path.\n\ -\n\ - LD_LIBRARY_PATH\n\ - System-wide library search order. This should be set\n\ - by the program invoking the proxy.\n\ -\n\ - DISPLAY On the X server side, the DISPLAY variable indicates\n\ - the location of the X11 server. When nxcomp is used\n\ - as a transport library, the DISPLAY may represent a\n\ - NX transport specification and options can passed in\n\ - the form nx/nx,option=value...\n\ -\n\ - XAUTHORITY This is the file containing the X11 authorization\n\ - cookie. If not set, the file is assumed to be in\n\ - the user's home (either NX_HOME or HOME).\n\ -\n\ -"; - -const char *GetUsageInfo() -{ - return UsageInfo; -} - -static const char CopyrightInfo[] = -"\ -Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com)\n\ -Copyright (c) 2008-2014 Oleksandr Shneyder \n\ -Copyright (c) 2014-2016 Ulrich Sibiller \n\ -Copyright (c) 2014-2016 Mihai Moldovan \n\ -Copyright (c) 2011-2016 Mike Gabriel \n\ -Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com)\n\ -\n\ -NXCOMP, NX protocol compression and NX extensions to this software\n\ -are copyright of the aforementioned persons and companies.\n\ -\n\ -Redistribution and use of the present software is allowed according\n\ -to terms specified in the file LICENSE.nxcomp which comes in the\n\ -source distribution.\n\ -\n\ -All rights reserved.\n\ -\n\ -NOTE: This software has received contributions from various other\n\ -contributors, only the core maintainers and supporters are listed as\n\ -copyright holders. Please contact us, if you feel you should be listed\n\ -as copyright holder, as well.\n\ -"; - -const char *GetCopyrightInfo() -{ - return CopyrightInfo; -} - -static const char OtherCopyrightInfo[] = -"\ -NX protocol compression is derived from DXPC project.\n\ -\n\ -Copyright (c) 1995,1996 Brian Pane\n\ -Copyright (c) 1996,1997 Zachary Vonler and Brian Pane\n\ -Copyright (c) 1999 Kevin Vigor and Brian Pane\n\ -Copyright (c) 2000,2003 Gian Filippo Pinzari and Brian Pane\n\ -\n\ -All rights reserved.\n\ -"; - -const char *GetOtherCopyrightInfo() -{ - return OtherCopyrightInfo; -} - -int _hostBigEndian = 0; -int _storeBigEndian = 0; - -const unsigned int IntMask[33] = -{ - 0x00000000, - 0x00000001, - 0x00000003, - 0x00000007, - 0x0000000f, - 0x0000001f, - 0x0000003f, - 0x0000007f, - 0x000000ff, - 0x000001ff, - 0x000003ff, - 0x000007ff, - 0x00000fff, - 0x00001fff, - 0x00003fff, - 0x00007fff, - 0x0000ffff, - 0x0001ffff, - 0x0003ffff, - 0x0007ffff, - 0x000fffff, - 0x001fffff, - 0x003fffff, - 0x007fffff, - 0x00ffffff, - 0x01ffffff, - 0x03ffffff, - 0x07ffffff, - 0x0fffffff, - 0x1fffffff, - 0x3fffffff, - 0x7fffffff, - 0xffffffff -}; - -unsigned int GetUINT(unsigned const char *buffer, int bigEndian) -{ - // - // It doesn't work on SPARCs if the buffer - // is not aligned to the word boundary. We - // should check the CPU, not the OS as this - // surely applies to other architectures. - // - - #ifndef __sun - - if (_hostBigEndian == bigEndian) - { - return *((unsigned short *) buffer); - } - - #else - - if (_hostBigEndian == bigEndian && ((unsigned int) buffer) & 0x1 == 0) - { - return *((unsigned short *) buffer); - } - - #endif - - unsigned int result; - - if (bigEndian) - { - result = *buffer; - - result <<= 8; - - result += buffer[1]; - } - else - { - result = buffer[1]; - - result <<= 8; - - result += *buffer; - } - - return result; -} - -unsigned int GetULONG(unsigned const char *buffer, int bigEndian) -{ - // - // It doesn't work on SPARCs if the buffer - // is not aligned to word the boundary. - // - - #ifndef __sun - - if (_hostBigEndian == bigEndian) - { - return *((unsigned int *) buffer); - } - - #else - - if (_hostBigEndian == bigEndian && ((unsigned int) buffer) & 0x3 == 0) - { - return *((unsigned int *) buffer); - } - - #endif - - const unsigned char *next = (bigEndian ? buffer : buffer + 3); - - unsigned int result = 0; - - for (int i = 0; i < 4; i++) - { - result <<= 8; - - result += *next; - - if (bigEndian) - { - next++; - } - else - { - next--; - } - } - - return result; -} - -void PutUINT(unsigned int value, unsigned char *buffer, int bigEndian) -{ - if (_hostBigEndian == bigEndian) - { - *((unsigned short *) buffer) = value; - - return; - } - - if (bigEndian) - { - buffer[1] = (unsigned char) (value & 0xff); - - value >>= 8; - - *buffer = (unsigned char) value; - } - else - { - *buffer = (unsigned char) (value & 0xff); - - value >>= 8; - - buffer[1] = (unsigned char) value; - } -} - -void PutULONG(unsigned int value, unsigned char *buffer, int bigEndian) -{ - if (_hostBigEndian == bigEndian) - { - *((unsigned int *) buffer) = value; - - return; - } - - if (bigEndian) - { - buffer += 3; - - for (int i = 4; i > 0; i--) - { - *buffer-- = (unsigned char) (value & 0xff); - - value >>= 8; - } - } - else - { - for (int i = 4; i > 0; i--) - { - *buffer++ = (unsigned char) (value & 0xff); - - value >>= 8; - } - } -} - -int CheckData(istream *fs) -{ - if (fs == NULL || fs -> fail()) - { - return -1; - } - - return 1; -} - -int CheckData(ostream *fs) -{ - if (fs == NULL || fs -> fail()) - { - return -1; - } - - return 1; -} - -int PutData(ostream *fs, const unsigned char *buffer, int size) -{ - fs -> write((char *) buffer, size); - - #ifdef DEBUG - *logofs << "PutData: Written " << size << " bytes with eof " - << fs -> eof() << " fail " << fs -> fail() << " and bad " - << fs -> bad() << ".\n" << logofs_flush; - #endif - - if (fs -> fail()) - { - return -1; - } - - return size; -} - -int GetData(istream *fs, unsigned char *buffer, int size) -{ - fs -> read((char *) buffer, size); - - #ifdef DEBUG - *logofs << "GetData: Read " << size << " bytes with eof " - << fs -> eof() << " fail " << fs -> fail() - << " and bad " << fs -> bad() << ".\n" - << logofs_flush; - #endif - - #ifdef __APPLE__ - - if (fs -> bad()) - { - return -1; - } - - #else - - if (fs -> fail()) - { - return -1; - } - - #endif - - return size; -} - -int FlushData(ostream *fs) -{ - fs -> flush(); - - if (fs -> fail()) - { - return -1; - } - - return 1; -} - -unsigned int RoundUp2(unsigned int x) -{ - unsigned int y = x / 2; - - y *= 2; - - if (y != x) - { - y += 2; - } - - return y; -} - -unsigned int RoundUp4(unsigned int x) -{ - unsigned int y = x / 4; - - y *= 4; - - if (y != x) - { - y += 4; - } - - return y; -} - -unsigned int RoundUp8(unsigned int x) -{ - unsigned int y = x / 8; - - y *= 8; - - if (y != x) - { - y += 8; - } - - return y; -} - -const char *DumpSignal(int signal) -{ - switch (signal) - { - case SIGCHLD: - { - return "SIGCHLD"; - } - case SIGUSR1: - { - return "SIGUSR1"; - } - case SIGUSR2: - { - return "SIGUSR2"; - } - case SIGHUP: - { - return "SIGHUP"; - } - case SIGINT: - { - return "SIGINT"; - } - case SIGTERM: - { - return "SIGTERM"; - } - case SIGPIPE: - { - return "SIGPIPE"; - } - case SIGALRM: - { - return "SIGALRM"; - } - case SIGVTALRM: - { - return "SIGVTALRM"; - } - case SIGWINCH: - { - return "SIGWINCH"; - } - case SIGIO: - { - return "SIGIO"; - } - case SIGTSTP: - { - return "SIGTSTP"; - } - case SIGTTIN: - { - return "SIGTTIN"; - } - case SIGTTOU: - { - return "SIGTTOU"; - } - case SIGSEGV: - { - return "SIGSEGV"; - } - case SIGABRT: - { - return "SIGABRT"; - } - default: - { - return "Unknown"; - } - } -} - -const char *DumpPolicy(int type) -{ - switch ((T_flush_policy) type) - { - case policy_immediate: - { - return "immediate"; - } - case policy_deferred: - { - return "deferred"; - } - default: - { - #ifdef PANIC - *logofs << "Misc: PANIC! Unknown policy type '" - << type << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unknown policy type '" - << type << "'.\n"; - - HandleCleanup(); - } - } -} - -const char *DumpAction(int type) -{ - T_store_action action = (T_store_action) type; - - if (action == IS_HIT) - { - return "is_hit"; - } - else if (action == IS_ADDED) - { - return "is_added"; - } - else if (action == is_discarded) - { - return "is_discarded"; - } - else if (action == is_removed) - { - return "is_removed"; - } - else - { - #ifdef PANIC - *logofs << "Misc: PANIC! Unknown store action '" - << type << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unknown store action '" - << type << "'.\n"; - - HandleCleanup(); - } -} - -const char *DumpState(int type) -{ - switch ((T_split_state) type) - { - case split_added: - { - return "split_added"; - } - case split_missed: - { - return "split_missed"; - } - case split_loaded: - { - return "split_loaded"; - } - case split_aborted: - { - return "split_aborted"; - } - case split_notified: - { - return "split_notified"; - } - default: - { - #ifdef PANIC - *logofs << "Misc: PANIC! Unknown split state '" - << type << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unknown split state '" - << type << "'.\n"; - - HandleCleanup(); - } - } -} - -const char *DumpControl(int code) -{ - switch ((T_proxy_code) code) - { - case code_new_x_connection: - { - return "code_new_x_connection"; - } - case code_new_cups_connection: - { - return "code_new_cups_connection"; - } - case code_new_aux_connection: - { - return "code_new_aux_connection"; - } - case code_new_smb_connection: - { - return "code_new_smb_connection"; - } - case code_new_media_connection: - { - return "code_new_media_connection"; - } - case code_switch_connection: - { - return "code_switch_connection"; - } - case code_drop_connection: - { - return "code_drop_connection"; - } - case code_finish_connection: - { - return "code_finish_connection"; - } - case code_begin_congestion: - { - return "code_begin_congestion"; - } - case code_end_congestion: - { - return "code_end_congestion"; - } - case code_alert_request: - { - return "code_alert_request"; - } - case code_alert_reply: - { - return "code_alert_reply"; - } - case code_reset_request: - { - return "code_reset_request"; - } - case code_reset_reply: - { - return "code_reset_reply"; - } - case code_load_request: - { - return "code_load_request"; - } - case code_load_reply: - { - return "code_load_reply"; - } - case code_save_request: - { - return "code_save_request"; - } - case code_save_reply: - { - return "code_save_reply"; - } - case code_shutdown_request: - { - return "code_shutdown_request"; - } - case code_shutdown_reply: - { - return "code_shutdown_reply"; - } - case code_control_token_request: - { - return "code_control_token_request"; - } - case code_control_token_reply: - { - return "code_control_token_reply"; - } - case code_configuration_request: - { - return "code_configuration_request"; - } - case code_configuration_reply: - { - return "code_configuration_reply"; - } - case code_statistics_request: - { - return "code_statistics_request"; - } - case code_statistics_reply: - { - return "code_statistics_reply"; - } - case code_new_http_connection: - { - return "code_new_http_connection"; - } - case code_sync_request: - { - return "code_sync_request"; - } - case code_sync_reply: - { - return "code_sync_reply"; - } - case code_new_font_connection: - { - return "code_new_font_connection"; - } - case code_new_slave_connection: - { - return "code_new_slave_connection"; - } - case code_finish_listeners: - { - return "code_finish_listeners"; - } - case code_split_token_request: - { - return "code_split_token_request"; - } - case code_split_token_reply: - { - return "code_split_token_reply"; - } - case code_data_token_request: - { - return "code_data_token_request"; - } - case code_data_token_reply: - { - return "code_data_token_reply"; - } - default: - { - #ifdef WARNING - *logofs << "Misc: WARNING! Unknown control code '" - << code << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Unknown control code '" - << code << "'.\n"; - - return "unknown"; - } - } -} - -const char *DumpSession(int code) -{ - switch ((T_session_mode) code) - { - case session_agent: - { - return "session_agent"; - } - case session_shadow: - { - return "session_shadow"; - } - case session_proxy: - { - return "session_proxy"; - } - default: - { - #ifdef WARNING - *logofs << "Misc: WARNING! Unknown session type '" - << code << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Unknown session type '" - << code << "'.\n"; - - return "unknown"; - } - } -} - -const char *DumpToken(int type) -{ - switch ((T_token_type) type) - { - case token_control: - { - return "token_control"; - } - case token_split: - { - return "token_split"; - } - case token_data: - { - return "token_data"; - } - default: - { - #ifdef WARNING - *logofs << "Misc: WARNING! Unknown token type '" - << type << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Unknown token type '" - << type << "'.\n"; - - return "unknown"; - } - } -} - -// -// Always include this in code as it is generally -// needed to test channels and split store. -// - -const char *DumpChecksum(const void *checksum) -{ - static char string[MD5_LENGTH * 2 + 1]; - - if (checksum != NULL) - { - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - sprintf(string + (i * 2), "%02X", ((unsigned char *) checksum)[i]); - } - } - else - { - strcpy(string, "null"); - } - - return string; -} - -// -// Define OPCODES here and in the channel -// if you want to log the opcode literal. -// - -#ifdef OPCODES - -const char *DumpOpcode(const int &opcode) -{ - switch (opcode) - { - case X_CreateWindow: - { - return "X_CreateWindow"; - } - case X_ChangeWindowAttributes: - { - return "X_ChangeWindowAttributes"; - } - case X_GetWindowAttributes: - { - return "X_GetWindowAttributes"; - } - case X_DestroyWindow: - { - return "X_DestroyWindow"; - } - case X_DestroySubwindows: - { - return "X_DestroySubwindows"; - } - case X_ChangeSaveSet: - { - return "X_ChangeSaveSet"; - } - case X_ReparentWindow: - { - return "X_ReparentWindow"; - } - case X_MapWindow: - { - return "X_MapWindow"; - } - case X_MapSubwindows: - { - return "X_MapSubwindows"; - } - case X_UnmapWindow: - { - return "X_UnmapWindow"; - } - case X_UnmapSubwindows: - { - return "X_UnmapSubwindows"; - } - case X_ConfigureWindow: - { - return "X_ConfigureWindow"; - } - case X_CirculateWindow: - { - return "X_CirculateWindow"; - } - case X_GetGeometry: - { - return "X_GetGeometry"; - } - case X_QueryTree: - { - return "X_QueryTree"; - } - case X_InternAtom: - { - return "X_InternAtom"; - } - case X_GetAtomName: - { - return "X_GetAtomName"; - } - case X_ChangeProperty: - { - return "X_ChangeProperty"; - } - case X_DeleteProperty: - { - return "X_DeleteProperty"; - } - case X_GetProperty: - { - return "X_GetProperty"; - } - case X_ListProperties: - { - return "X_ListProperties"; - } - case X_SetSelectionOwner: - { - return "X_SetSelectionOwner"; - } - case X_GetSelectionOwner: - { - return "X_GetSelectionOwner"; - } - case X_ConvertSelection: - { - return "X_ConvertSelection"; - } - case X_SendEvent: - { - return "X_SendEvent"; - } - case X_GrabPointer: - { - return "X_GrabPointer"; - } - case X_UngrabPointer: - { - return "X_UngrabPointer"; - } - case X_GrabButton: - { - return "X_GrabButton"; - } - case X_UngrabButton: - { - return "X_UngrabButton"; - } - case X_ChangeActivePointerGrab: - { - return "X_ChangeActivePointerGrab"; - } - case X_GrabKeyboard: - { - return "X_GrabKeyboard"; - } - case X_UngrabKeyboard: - { - return "X_UngrabKeyboard"; - } - case X_GrabKey: - { - return "X_GrabKey"; - } - case X_UngrabKey: - { - return "X_UngrabKey"; - } - case X_AllowEvents: - { - return "X_AllowEvents"; - } - case X_GrabServer: - { - return "X_GrabServer"; - } - case X_UngrabServer: - { - return "X_UngrabServer"; - } - case X_QueryPointer: - { - return "X_QueryPointer"; - } - case X_GetMotionEvents: - { - return "X_GetMotionEvents"; - } - case X_TranslateCoords: - { - return "X_TranslateCoords"; - } - case X_WarpPointer: - { - return "X_WarpPointer"; - } - case X_SetInputFocus: - { - return "X_SetInputFocus"; - } - case X_GetInputFocus: - { - return "X_GetInputFocus"; - } - case X_QueryKeymap: - { - return "X_QueryKeymap"; - } - case X_OpenFont: - { - return "X_OpenFont"; - } - case X_CloseFont: - { - return "X_CloseFont"; - } - case X_QueryFont: - { - return "X_QueryFont"; - } - case X_QueryTextExtents: - { - return "X_QueryTextExtents"; - } - case X_ListFonts: - { - return "X_ListFonts"; - } - case X_ListFontsWithInfo: - { - return "X_ListFontsWithInfo"; - } - case X_SetFontPath: - { - return "X_SetFontPath"; - } - case X_GetFontPath: - { - return "X_GetFontPath"; - } - case X_CreatePixmap: - { - return "X_CreatePixmap"; - } - case X_FreePixmap: - { - return "X_FreePixmap"; - } - case X_CreateGC: - { - return "X_CreateGC"; - } - case X_ChangeGC: - { - return "X_ChangeGC"; - } - case X_CopyGC: - { - return "X_CopyGC"; - } - case X_SetDashes: - { - return "X_SetDashes"; - } - case X_SetClipRectangles: - { - return "X_SetClipRectangles"; - } - case X_FreeGC: - { - return "X_FreeGC"; - } - case X_ClearArea: - { - return "X_ClearArea"; - } - case X_CopyArea: - { - return "X_CopyArea"; - } - case X_CopyPlane: - { - return "X_CopyPlane"; - } - case X_PolyPoint: - { - return "X_PolyPoint"; - } - case X_PolyLine: - { - return "X_PolyLine"; - } - case X_PolySegment: - { - return "X_PolySegment"; - } - case X_PolyRectangle: - { - return "X_PolyRectangle"; - } - case X_PolyArc: - { - return "X_PolyArc"; - } - case X_FillPoly: - { - return "X_FillPoly"; - } - case X_PolyFillRectangle: - { - return "X_PolyFillRectangle"; - } - case X_PolyFillArc: - { - return "X_PolyFillArc"; - } - case X_PutImage: - { - return "X_PutImage"; - } - case X_GetImage: - { - return "X_GetImage"; - } - case X_PolyText8: - { - return "X_PolyText8"; - } - case X_PolyText16: - { - return "X_PolyText16"; - } - case X_ImageText8: - { - return "X_ImageText8"; - } - case X_ImageText16: - { - return "X_ImageText16"; - } - case X_CreateColormap: - { - return "X_CreateColormap"; - } - case X_FreeColormap: - { - return "X_FreeColormap"; - } - case X_CopyColormapAndFree: - { - return "X_CopyColormapAndFree"; - } - case X_InstallColormap: - { - return "X_InstallColormap"; - } - case X_UninstallColormap: - { - return "X_UninstallColormap"; - } - case X_ListInstalledColormaps: - { - return "X_ListInstalledColormaps"; - } - case X_AllocColor: - { - return "X_AllocColor"; - } - case X_AllocNamedColor: - { - return "X_AllocNamedColor"; - } - case X_AllocColorCells: - { - return "X_AllocColorCells"; - } - case X_AllocColorPlanes: - { - return "X_AllocColorPlanes"; - } - case X_FreeColors: - { - return "X_FreeColors"; - } - case X_StoreColors: - { - return "X_StoreColors"; - } - case X_StoreNamedColor: - { - return "X_StoreNamedColor"; - } - case X_QueryColors: - { - return "X_QueryColors"; - } - case X_LookupColor: - { - return "X_LookupColor"; - } - case X_CreateCursor: - { - return "X_CreateCursor"; - } - case X_CreateGlyphCursor: - { - return "X_CreateGlyphCursor"; - } - case X_FreeCursor: - { - return "X_FreeCursor"; - } - case X_RecolorCursor: - { - return "X_RecolorCursor"; - } - case X_QueryBestSize: - { - return "X_QueryBestSize"; - } - case X_QueryExtension: - { - return "X_QueryExtension"; - } - case X_ListExtensions: - { - return "X_ListExtensions"; - } - case X_ChangeKeyboardMapping: - { - return "X_ChangeKeyboardMapping"; - } - case X_GetKeyboardMapping: - { - return "X_GetKeyboardMapping"; - } - case X_ChangeKeyboardControl: - { - return "X_ChangeKeyboardControl"; - } - case X_GetKeyboardControl: - { - return "X_GetKeyboardControl"; - } - case X_Bell: - { - return "X_Bell"; - } - case X_ChangePointerControl: - { - return "X_ChangePointerControl"; - } - case X_GetPointerControl: - { - return "X_GetPointerControl"; - } - case X_SetScreenSaver: - { - return "X_SetScreenSaver"; - } - case X_GetScreenSaver: - { - return "X_GetScreenSaver"; - } - case X_ChangeHosts: - { - return "X_ChangeHosts"; - } - case X_ListHosts: - { - return "X_ListHosts"; - } - case X_SetAccessControl: - { - return "X_SetAccessControl"; - } - case X_SetCloseDownMode: - { - return "X_SetCloseDownMode"; - } - case X_KillClient: - { - return "X_KillClient"; - } - case X_RotateProperties: - { - return "X_RotateProperties"; - } - case X_ForceScreenSaver: - { - return "X_ForceScreenSaver"; - } - case X_SetPointerMapping: - { - return "X_SetPointerMapping"; - } - case X_GetPointerMapping: - { - return "X_GetPointerMapping"; - } - case X_SetModifierMapping: - { - return "X_SetModifierMapping"; - } - case X_GetModifierMapping: - { - return "X_GetModifierMapping"; - } - case X_NoOperation: - { - return "X_NoOperation"; - } - case X_NXInternalGenericData: - { - return "X_NXInternalGenericData"; - } - // - // case X_NXInternalGenericReply: - // { - // return "X_NXInternalGenericReply"; - // } - // - case X_NXInternalGenericRequest: - { - return "X_NXInternalGenericRequest"; - } - case X_NXInternalShapeExtension: - { - return "X_NXInternalShapeExtension"; - } - case X_NXGetControlParameters: - { - return "X_NXGetControlParameters"; - } - case X_NXGetCleanupParameters: - { - return "X_NXGetCleanupParameters"; - } - case X_NXGetImageParameters: - { - return "X_NXGetImageParameters"; - } - case X_NXGetUnpackParameters: - { - return "X_NXGetUnpackParameters"; - } - case X_NXGetShmemParameters: - { - return "X_NXGetShmemParameters"; - } - case X_NXGetFontParameters: - { - return "X_NXGetFontParameters"; - } - case X_NXSetExposeParameters: - { - return "X_NXSetExposeParameters"; - } - case X_NXSetCacheParameters: - { - return "X_NXSetCacheParameters"; - } - case X_NXStartSplit: - { - return "X_NXStartSplit"; - } - case X_NXEndSplit: - { - return "X_NXEndSplit"; - } - case X_NXSplitData: - { - return "X_NXSplitData"; - } - case X_NXSplitEvent: - { - return "X_NXSplitEvent"; - } - case X_NXCommitSplit: - { - return "X_NXCommitSplit"; - } - case X_NXFinishSplit: - { - return "X_NXFinishSplit"; - } - case X_NXAbortSplit: - { - return "X_NXAbortSplit"; - } - case X_NXFreeSplit: - { - return "X_NXFreeSplit"; - } - case X_NXSetUnpackGeometry: - { - return "X_NXSetUnpackGeometry"; - } - case X_NXSetUnpackColormap: - { - return "X_NXSetUnpackColormap"; - } - case X_NXSetUnpackAlpha: - { - return "X_NXSetUnpackAlpha"; - } - case X_NXPutPackedImage: - { - return "X_NXPutPackedImage"; - } - case X_NXFreeUnpack: - { - return "X_NXFreeUnpack"; - } - default: - { - if (opcode > 127) - { - return "Extension"; - } - else - { - return "?"; - } - } - } -} - -#else /* #ifdef OPCODES */ - -const char *DumpOpcode(const int &opcode) -{ - return "?"; -} - -#endif /* #ifdef OPCODES */ - -void DumpData(const unsigned char *buffer, unsigned int size) -{ - if (buffer != NULL) - { - unsigned int i = 0; - - while (i < size) - { - *logofs << "[" << i << "]\t"; - - for (unsigned int ii = 0; i < size && ii < 8; i++, ii++) - { - *logofs << (unsigned int) (buffer[i]) << "\t"; - } - - *logofs << "\n" << logofs_flush; - } - } -} - -void DumpChecksum(const unsigned char *buffer, unsigned int size) -{ - if (buffer != NULL) - { - md5_byte_t md5_digest[MD5_LENGTH]; - - md5_state_t md5_state; - - md5_init(&md5_state); - - md5_append(&md5_state, buffer, size); - - md5_finish(&md5_state, md5_digest); - - char md5_string[MD5_LENGTH * 2 + 1]; - - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - sprintf(md5_string + (i * 2), "%02X", md5_digest[i]); - } - - *logofs << "[" << md5_string << "]" << logofs_flush; - } -} - -void DumpBlockChecksums(const unsigned char *buffer, - unsigned int size, unsigned int block) -{ - for (unsigned int i = 0; i < (size / block); i++) - { - *logofs << "[" << i * block << "]"; - - DumpChecksum(buffer + (i * block), block); - - *logofs << "\n"; - } - - if (size % block > 0) - { - *logofs << "[" << size / block * block << "]"; - - DumpChecksum(buffer + (size / block * block), size % block); - - *logofs << "\n"; - } -} - -void DumpHexData(const unsigned char *buffer, unsigned int size) -{ - char message [65536]; - char ascii [17]; - - unsigned int index = 0; - unsigned int linescan = 0; - unsigned int index_ascii = 0; - - sprintf (message,"\n#### Start Dump Buffer of [%.5d] Bytes ####\n\n",size); - - *logofs << message << logofs_flush; - - // - // "Index 0 1 2 3 4 5 6 7 8 9 a b c d e f Ascii " - // "----- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ----------------" - // "00000 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................" - // - - sprintf (message,"Index 0 1 2 3 4 5 6 7 8 9 a b c d e f Ascii \n"); - *logofs << message << logofs_flush; - sprintf (message,"----- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ----------------\n"); - *logofs << message << logofs_flush; - - index = 0; - - while (index < size) - { - memset (ascii, ' ', sizeof(ascii)); - - ascii[16] = '\0'; - - sprintf (message,"%.5d ", index); - - for (index_ascii = 0, linescan = index; - ((index < (linescan + 16)) && (index < size)); - index++, index_ascii++) - { - if (isprint(buffer [index])) - { - ascii[index_ascii] = buffer [index]; - } - else - { - ascii[index_ascii] = '.'; - } - - sprintf (&message [strlen (message)],"%.2x ", (unsigned char) buffer [index]); - } - - for (linescan = index_ascii; linescan < 16; linescan++) - { - strcat (&message [strlen (message)], " "); - } - - sprintf (&message [strlen (message)]," %s\n", ascii); - - *logofs << message << logofs_flush; - } - - sprintf (message,"\n#### End Dump Buffer ####\n\n"); - - *logofs << message << logofs_flush; -} diff --git a/nxcomp/Misc.h b/nxcomp/Misc.h deleted file mode 100644 index 997630137..000000000 --- a/nxcomp/Misc.h +++ /dev/null @@ -1,279 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Misc_H -#define Misc_H - -#include -#include - -#include -#include - -#ifdef __sun - -#include - -#endif - -using namespace std; - -// -// This is MD5 length. -// - -#define MD5_LENGTH 16 - -// -// Error handling macros. -// - -#define ESET(e) (errno = (e)) -#define EGET() (errno) -#define ESTR() strerror(errno) - -// -// TCP port offset applied to NX port specification. -// - -extern const int DEFAULT_NX_PROXY_PORT_OFFSET; - -// -// Default TCP port used by client proxy to listen -// to X clients and by server proxy to connect to -// remote. -// - -extern const int DEFAULT_NX_PROXY_PORT; - -// -// Default X display number that client -// proxy imitates. -// - -extern const int DEFAULT_NX_X_PORT; - -// -// Establish the port offsets for the additional -// services. -// - -extern const int DEFAULT_NX_CUPS_PORT_OFFSET; -extern const int DEFAULT_NX_SMB_PORT_OFFSET; -extern const int DEFAULT_NX_MEDIA_PORT_OFFSET; -extern const int DEFAULT_NX_AUX_PORT_OFFSET; -extern const int DEFAULT_NX_HTTP_PORT_OFFSET; -extern const int DEFAULT_NX_FONT_PORT_OFFSET; - -// -// Slave channels can be originated by both sides -// so they need to have different port offsets -// in the case the user runs both proxies on the -// same host. -// - -extern const int DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET; -extern const int DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET; - -// -// NX proxy binds to all network interfaces by default -// With the -loopback parameter, you can switch -// over to binding to the loopback device only. -// - -extern const int DEFAULT_LOOPBACK_BIND; - -// -// Return strings containing various info. -// - -const char *GetUsageInfo(); -const char *GetCopyrightInfo(); -const char *GetOtherCopyrightInfo(); - -// -// Define this if you want immediate flush of -// the log output. -// - -#define FLUSH_LOGOFS - -// -// Global objects providing shared functions. -// - -class Auth; -class Control; -class Statistics; - -extern Auth *auth; -extern Control *control; -extern Statistics *statistics; - -// -// Log file. -// - -extern ostream *logofs; - -// -// Cleanup code. -// - -void HandleAbort() __attribute__((noreturn)); -void HandleShutdown() __attribute__((noreturn)); - -extern "C" -{ - void HandleCleanup(int code = 0) __attribute__((noreturn)); - void HandleCleanupForReconnect(); -} - -// -// Manage signal handlers. -// - -void DisableSignals(); -void EnableSignals(); - -// -// Manage timers. -// - -void SetTimer(int value); -void ResetTimer(); - -// -// Show a dialog asking the user if he/she -// wants to close the current session. Look -// in the alerts file for the known critical -// events. -// - -void HandleAlert(int code, int local); - -// -// Run the callback registered by the proxy -// or the agent. -// - -void KeeperCallback(); -void FlushCallback(int length); - -// -// Return the string literal corresponding -// the value. -// - -const char *DumpSignal(int signal); -const char *DumpPolicy(int type); -const char *DumpControl(int code); -const char *DumpSession(int code); -const char *DumpAction(int type); -const char *DumpState(int type); -const char *DumpToken(int type); - -// -// Print out content of buffer to log file. -// You need to define DUMP or OPCODES in -// the source to have these compiled. -// - -const char *DumpOpcode(const int &opcode); -const char *DumpChecksum(const void *checksum); - -void DumpData(const unsigned char *data, unsigned int length); -void DumpHexData(const unsigned char *data, unsigned int length); -void DumpChecksum(const unsigned char *data, unsigned int length); -void DumpBlockChecksums(const unsigned char *data, unsigned int length, - unsigned int block); - -// -// Defines logofs_flush as an empty string to -// avoid calling the corresponding ostream's -// flush() function. -// - -#ifdef FLUSH_LOGOFS - -#define logofs_flush "" ; logofs -> flush() - -#else - -#define logofs_flush "" - -#endif - -// -// Is the host where local proxy is running -// big-endian? -// - -extern int _hostBigEndian; -extern int _storeBigEndian; - -inline void setHostBigEndian(int flag) -{ - _hostBigEndian = flag; -} - -inline int hostBigEndian() -{ - return _hostBigEndian; -} - -inline int storeBigEndian() -{ - return _storeBigEndian; -} - -extern const unsigned int IntMask[33]; - -unsigned int GetUINT(unsigned const char *buffer, int bigEndian); -unsigned int GetULONG(unsigned const char *buffer, int bigEndian); -void PutUINT(unsigned int value, unsigned char *buffer, int bigEndian); -void PutULONG(unsigned int value, unsigned char *buffer, int bigEndian); - -inline void CleanData(unsigned char *buffer, int size) -{ - unsigned char *end = buffer + size; - - while (buffer < end) - { - *buffer++ = 0x00; - } -} - -int CheckData(istream *fs); -int CheckData(ostream *fs); -int PutData(ostream *fs, const unsigned char *buffer, int size); -int GetData(istream *fs, unsigned char *buffer, int size); -int FlushData(ostream *fs); - -unsigned int RoundUp2(unsigned int x); -unsigned int RoundUp4(unsigned int x); -unsigned int RoundUp8(unsigned int x); - -#endif /* Misc_H */ diff --git a/nxcomp/NX.h b/nxcomp/NX.h deleted file mode 100644 index 7ec79b4b1..000000000 --- a/nxcomp/NX.h +++ /dev/null @@ -1,471 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef NX_H -#define NX_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include -#include -#include -#include - -#define NX_FD_ANY -1 - -#define NX_MODE_ANY -1 -#define NX_MODE_CLIENT 1 -#define NX_MODE_SERVER 2 - -#define NX_DISPLAY_ANY NULL - -#define NX_SIGNAL_ANY -1 -#define NX_SIGNAL_ENABLE 1 -#define NX_SIGNAL_DISABLE 2 -#define NX_SIGNAL_RAISE 3 -#define NX_SIGNAL_FORWARD 4 - -#define NX_POLICY_IMMEDIATE 1 -#define NX_POLICY_DEFERRED 2 - -#define NX_ALERT_REMOTE 0 -#define NX_ALERT_LOCAL 1 - -#define NX_HANDLER_FLUSH 0 -#define NX_HANDLER_STATISTICS 1 - -#define NX_STATISTICS_PARTIAL 0 -#define NX_STATISTICS_TOTAL 1 - -#define NX_CHANNEL_X11 0 -#define NX_CHANNEL_CUPS 1 -#define NX_CHANNEL_SMB 2 -#define NX_CHANNEL_MEDIA 3 -#define NX_CHANNEL_HTTP 4 -#define NX_CHANNEL_FONT 5 -#define NX_CHANNEL_SLAVE 6 - -#define NX_FILE_SESSION 0 -#define NX_FILE_ERRORS 1 -#define NX_FILE_OPTIONS 2 -#define NX_FILE_STATS 3 - -/* - * The following are the new interfaces to the NX transport. The - * NX proxy software is now intended to be run as a library of a - * higher level communication manager (nxssh, nxhttp, nxrtp, etc, - * not only nxproxy). This is a work-in-progress, so expect these - * interfaces to change in future. At the present moment, as an - * example, there is no provision for creating and managing mul- - * tiple proxy connections. - */ - -/* - * Attach a NX transport to the provided descriptor. This should be - * done after having created a pair of connected sockets. - */ - -extern int NXTransCreate(int fd, int mode, const char *options); - -/* - * Tell the proxy to use the second descriptor as its own end of - * the internal connection to the NX agent. The NX agent will use - * the first descriptor. Setting an agent connection will have the - * effect of disabling further X client connections and, if it is - * possible, will trigger the use of the memory-to-memory transport. - */ - -extern int NXTransAgent(int fd[2]); - -/* - * Prepare the file sets and the timeout for a later execution of - * the select(). The masks and the timeout must persist across all - * the calls, so if you don't need any of the values, it is requi- - * red that you create empty masks and a default timeout. To save - * a check at each run, all the functions below assume that valid - * pointers are passed. - */ - -extern int NXTransPrepare(int *maxfds, fd_set *readfds, - fd_set *writefds, struct timeval *timeout); - -/* - * Call select() to find out the descriptors in the sets having - * pending data. - */ - -extern int NXTransSelect(int *result, int *error, int *maxfds, fd_set *readfds, - fd_set *writefds, struct timeval *timeout); - -/* - * Perform the required I/O on all the NX descriptors having pen- - * ding data. This can include reading and writing to the NX chan- - * nels, encoding and decoding the proxy data or managing any of - * the other NX resources. - */ - -extern int NXTransExecute(int *result, int *error, int *maxfds, fd_set *readfds, - fd_set *writefds, struct timeval *timeout); - -/* - * Run an empty loop, giving to the NX transport a chance to check - * its descriptors. - */ - -extern int NXTransContinue(struct timeval *timeout); - -/* - * Perform I/O on the given descriptors. If memory-to-memory trans- - * port has been activated and the descriptor is recognized as a - * valid agent connection, then the functions will read and write - * the data directly to the proxy buffer, otherwise the correspond- - * ing network operation will be performed. - */ - -extern int NXTransRead(int fd, char *data, int size); -extern int NXTransWrite(int fd, char *data, int size); -extern int NXTransReadable(int fd, int *readable); - -extern int NXTransReadVector(int fd, struct iovec *iovdata, int iovsize); -extern int NXTransWriteVector(int fd, struct iovec *iovdata, int iovsize); - -extern int NXTransClose(int fd); - -/* - * Return true if the NX transport is running. The fd parameter can - * be either the local descriptor attached to the NX transport or - * NX_FD_ANY. - */ - -extern int NXTransRunning(int fd); - -/* - * Close down the NX transport and free all the allocated resources. - * The fd parameter can be either the local descriptor or NX_FD_ANY. - * This must be explicitly called by the agent before the proxy can - * start the tear down procedure. - */ - -extern int NXTransDestroy(int fd); - -/* - * Tell to the proxy how to handle the standard POSIX signals. For - * example, given the SIGINT signal, the caller can specify any of - * the following actions: - * - * NX_SIGNAL_ENABLE: A signal handler will have to be installed by - * the library, so that it can be intercepted by - * the proxy. - * - * NX_SIGNAL_DISABLE: The signal will be handled by the caller and, - * eventually, forwarded to the proxy by calling - * NXTransSignal() explicitly. - * - * NX_SIGNAL_RAISE: The signal must be handled now, as if it had - * been delivered by the operating system. This - * function can be called by the agent with the - * purpose of propagating a signal to the proxy. - * - * NX_SIGNAL_FORWARD: A signal handler will have to be installed by - * the library but the library will have to call - * the original signal handler when the signal - * is received. - * - * As a rule of thumb, agents should let the proxy handle SIGUSR1 - * and SIGUSR2, used for producing the NX protocol statistics, and - * SIGHUP, used for disconnecting the NX transport. - * - * The following signals are blocked by default upon creation of the - * NX transport: - * - * SIGCHLD These signals should be always put under the control - * SIGUSR1 of the proxy. If agents are intercepting them, agents - * SIGUSR2 should later call NXTransSignal(..., NX_SIGNAL_RAISE) - * SIGHUP to forward the signal to the proxy. As an alternative - * they can specify a NX_SIGNAL_FORWARD action, so they, - * in turn, can be notified about the signal. This can - * be especially useful for SIGCHLD. - * - * SIGINT These signals should be intercepted by agents. Agents - * SIGTERM should ensure that NXTransDestroy() is called before - * exiting, to give the proxy a chance to shut down the - * NX transport. - * - * SIGPIPE This signal is blocked by the proxy, but not used to - * implement any functionality. It can be handled by the - * NX agent without affecting the proxy. - * - * SIGALRM This is now used by the proxy and agents should not - * redefine it. Agents can use the signal to implement - * their own timers but should not interleave calls to - * the NX transport and should restore the old handler - * when the timeout is raised. - * - * SIGVTALRM These signals are not used but may be used in future - * SIGWINCH versions of the library. - * SIGIO - * SIGTSTP - * SIGTTIN - * SIGTTOU - * - * By calling NXTransSignal(..., NX_SIGNAL_DISABLE) nxcomp will res- - * tore the signal handler that was saved at the time the proxy hand- - * ler was installed. This means that you should call the function - * just after the XOpenDisplay() or any other function used to init- - * ialize the NX transport. - */ - -extern int NXTransSignal(int signal, int action); - -/* - * Return a value between 0 and 9 indicating the congestion level - * based on the tokens still available. A value of 9 means that - * the link is congested and no further data can be sent. - */ - -extern int NXTransCongestion(int fd); - -/* - * Let the application to be notified by the proxy when an event oc- - * curs. The parameter, as set at the time the handler is installed, - * is passed each time to the callback function. The parameter is - * presumably the display pointer, given that at the present moment - * the NX transport doesn't have access to the display structure and - * so wouldn't be able to determine the display to pass to the call- - * back function. - * - * NX_HANDLER_FLUSH: The handler function is called when some - * more data has been written to the proxy - * link. - * - * The data is the number of bytes written. - * - * NX_HANDLER_STATISTICS: This handler is called to let the agent - * include arbitrary data in the transport - * statistics. The parameter, in this case, - * is a pointer to a pointer to a null term- - * inated string. The pointer is set at the - * time the handler is registered. The point- - * ed string will have to be filled by the - * agent with its statistics data. - * - * The data can be NX_STATISTICS_PARTIAL or NX_STATISTICS_TOTAL. The - * agent can refer to the value by using the NXStatisticsPartial and - * NXStatisticsTotal constants defined in NXvars.h. - * - * Note that these interfaces are used by Xlib and nxcompext. Agents - * should never call these interfaces directly, but use the nxcompext - * wrapper. - */ - -extern int NXTransHandler(int fd, int type, void (*handler)(void *parameter, - int reason), void *parameter); - -/* - * Set the policy to be used by the NX transport to write data to the - * proxy link: - * - * NX_POLICY_IMMEDIATE: When set to immediate, the proxy will try to - * write the data just after having encoded it. - * - * NX_POLICY_DEFERRED: When policy is set to deferred, data will be - * accumulated in a buffer and written to the - * remote proxy when NXTransFlush() is called by - * the agent. - */ - -extern int NXTransPolicy(int fd, int type); - -/* - * Query the number of bytes that have been accumulated for a deferred - * flush. - */ - -extern int NXTransFlushable(int fd); - -/* - * Tell to the NX transport to write all the accumulated data to the - * remote proxy. - */ - -extern int NXTransFlush(int fd); - -/* - * Create a new channel of the given type. It returns 1 on success, - * 0 if the NX transport is not running, or -1 in the case of error. - * On success, the descriptor provided by the caller can be later - * used for the subsequent I/O. The type parameter not only tells to - * the proxy the remote port where the channel has to be connected, - * but also gives a hint about the type of data that will be carried - * by the channel, so that the proxy can try to optimize the traffic - * on the proxy link. - * - * NX_CHANNEL_X: The channel will carry X traffic and it - * will be connected to the remote X display. - * - * NX_CHANNEL_CUPS: The channel will carry CUPS/IPP protocol. - * - * NX_CHANNEL_SMB: The channel will carry SMB/CIFS protocol. - * - * NX_CHANNEL_MEDIA: The channel will transport audio or other - * multimedia data. - * - * NX_CHANNEL_HTTP: The channel will carry HTTP protocol. - * - * NX_CHANNEL_FONT: The channel will forward a X font server - * connection. - * - * Only a proxy running at the NX server/X client side will be able - * to create a X, CUPS, SMB, MEDIA and HTTP channel. A proxy running - * at the NX client/X server side can create font server connections. - * The channel creation will also fail if the remote end has not been - * set up to forward the connection. - * - * To create a new channel the agent will have to set up a socketpair - * and pass to the proxy one of the socket descriptors. - * - * Example: - * - * #include - * #include - * - * int fds[2]; - * - * if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) - * { - * ... - * } - * else - * { - * // - * // Use fds[0] locally and let the - * // proxy use fds[1]. - * // - * - * if (NXTransChannel(NX_FD_ANY, fds[1], NX_CHANNEL_X) <= 0) - * { - * ... - * } - * - * // - * // The agent can now use fds[0] in - * // read(), write() and select() - * // system calls. - * // - * - * ... - * } - * - * Note that all the I/O on the descriptor should be non-blocking, to - * give a chance to the NX transport to run in the background and handle - * the data that will be fed to the agent's side of the socketpair. This - * will happen automatically, as long as the agent uses the XSelect() - * version of the select() function (as it is normal whenever performing - * Xlib I/O). In all the other cases, like presumably in the agent's main - * loop, the agent will have to loop through NXTransPrepare(), NXTrans- - * Select() and NXTransExecute() functions explicitly, adding to the sets - * the descriptors that are awaited by the agent. Please check the imple- - * mentation of _XSelect() in nx-X11/lib/X11/XlibInt.c for an example. - */ - -extern int NXTransChannel(int fd, int channelfd, int type); - -/* - * Return the name of the files used by the proxy for the current session. - * - * The type parameter can be: - * - * NX_FILE_SESSION: Usually the file 'session' in the user's session - * directory. - * - * NX_FILE_ERRORS: The file used for the diagnostic output. Usually - * the file 'errors' in the session directory. - * - * NX_FILE_OPTIONS: The file containing the NX options, if any. - * - * NX_FILE_STATS: The file used for the statistics output. - * - * The returned string is allocated in static memory. The caller should - * copy the string upon returning from the function, without freeing the - * pointer. - */ - -extern const char *NXTransFile(int type); - -/* - * Return the time in milliseconds elapsed since the last call to this - * same function. - */ - -extern long NXTransTime(void); - -/* - * Other interfaces to the internal transport functions. - */ - -extern int NXTransProxy(int fd, int mode, const char *display); - -extern int NXTransClient(const char *display); - -extern int NXTransDialog(const char *caption, const char *message, - const char *window, const char *type, int local, - const char *display); - -extern int NXTransAlert(int code, int local); - -extern int NXTransWatchdog(int timeout); - -extern int NXTransKeeper(int caches, int images, const char *root); - -extern void NXTransExit(int code) __attribute__((noreturn)); - -extern int NXTransParseCommandLine(int argc, const char **argv); -extern int NXTransParseEnvironment(const char *env, int force); - -extern void NXTransCleanup(void) __attribute__((noreturn)); - -/* - * Cleans up the global and local state - * (the same way as NXTransCleanup does) - * but does not exit the process - * Needed for IOS platform - */ -extern void NXTransCleanupForReconnect(void); - -extern const char* NXVersion(void); -extern int NXMajorVersion(void); -extern int NXMinorVersion(void); -extern int NXPatchVersion(void); -extern int NXMaintenancePatchVersion(void); - -#ifdef __cplusplus -} -#endif - -#endif /* NX_H */ diff --git a/nxcomp/NXalert.h b/nxcomp/NXalert.h deleted file mode 100644 index dca2f44ca..000000000 --- a/nxcomp/NXalert.h +++ /dev/null @@ -1,276 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef NXalert_H -#define NXalert_H - -#define ALERT_CAPTION_PREFIX "NX - " - -#define INTERNAL_ERROR_ALERT 1 -#define INTERNAL_ERROR_ALERT_TYPE "error" -#define INTERNAL_ERROR_ALERT_STRING \ -"\ -An unrecoverable internal error was detected.\n\ -Press OK to terminate the current session.\n\ -" - -#define CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT 2 -#define CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_TYPE "yesno" -#define CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_STRING \ -"\ -One of the applications currently in use is not responding.\n\ -Do you want to terminate the current session?\n\ -" - -#define CLOSE_DEAD_X_CONNECTION_SERVER_ALERT 3 -#define CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_TYPE "yesno" -#define CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_STRING \ -"\ -One of the applications did not behave correctly and caused\n\ -the X server to stop responding in a timely fashion. Do you\n\ -want to terminate the current session?\n\ -" - -#define CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT 4 -#define CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT_TYPE NULL -#define CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT_STRING NULL - -#define CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT 5 -#define CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE "yesno" -#define CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING \ -"\ -No response received from the remote server.\n\ -Do you want to terminate the current session?\n\ -" - -#define RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT 6 -#define RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT_TYPE NULL -#define RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT_STRING NULL - -#define RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT 7 -#define RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE "yesno" -#define RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING \ -"\ -Connection with remote server was shut down. NX will try\n\ -to establish a new server connection. Session could have\n\ -been left in a unusable state. Do you want to terminate\n\ -the session?\n\ -" - -#define CLOSE_UNRESPONSIVE_X_SERVER_ALERT 8 -#define CLOSE_UNRESPONSIVE_X_SERVER_ALERT_TYPE "panic" -#define CLOSE_UNRESPONSIVE_X_SERVER_ALERT_STRING \ -"\ -You pressed the key sequence CTRL+ALT+SHIFT+ESC.\n\ -This is probably because your X server has become\n\ -unresponsive. Session will be terminated in 30\n\ -seconds unless you abort the procedure by pressing\n\ -the Cancel button.\n\ -" - -#define WRONG_PROXY_VERSION_ALERT 9 -#define WRONG_PROXY_VERSION_ALERT_TYPE "ok" -#define WRONG_PROXY_VERSION_ALERT_STRING \ -"\ -Local NX libraries version " VERSION " do not match the NX\n\ -version of the remote server. Please check the error\n\ -log on the server to find out which client version you\n\ -need to install to be able to access this server.\n\ -" - -#define FAILED_PROXY_CONNECTION_CLIENT_ALERT 10 -#define FAILED_PROXY_CONNECTION_CLIENT_ALERT_TYPE NULL -#define FAILED_PROXY_CONNECTION_CLIENT_ALERT_STRING NULL - -#define FAILED_PROXY_CONNECTION_SERVER_ALERT 11 -#define FAILED_PROXY_CONNECTION_SERVER_ALERT_TYPE "yesno" -#define FAILED_PROXY_CONNECTION_SERVER_ALERT_STRING \ -"\ -Could not yet establish the connection to the remote\n\ -proxy. Do you want to terminate the current session?\n\ -" - -#define MISSING_PROXY_CACHE_ALERT 12 -#define MISSING_PROXY_CACHE_ALERT_TYPE "ok" -#define MISSING_PROXY_CACHE_ALERT_STRING \ -"\ -NX was unable to negotiate a cache for this session.\n\ -This may happen if this is the first time you run a\n\ -session on this server or if cache was corrupted or\n\ -produced by an incompatible NX version.\n\ -" - -#define ABORT_PROXY_CONNECTION_ALERT 13 -#define ABORT_PROXY_CONNECTION_ALERT_TYPE "ok" -#define ABORT_PROXY_CONNECTION_ALERT_STRING \ -"\ -The connection with the remote server was shut down.\n\ -Please check the state of your network connection.\n\ -" - -/* - * The one below is a special alert, used to close - * a previous alert that is running on the given - * side. This can be used to get rid of a message - * that has ceased to hold true. - */ - -#define DISPLACE_MESSAGE_ALERT 14 -#define DISPLACE_MESSAGE_ALERT_TYPE NULL -#define DISPLACE_MESSAGE_ALERT_STRING NULL - -/* - * These are the other alert messages that were - * added in the 1.5.0 release. The first is never - * shown and is intended just for testing. - */ - -#define GREETING_MESSAGE_ALERT 15 -#define GREETING_MESSAGE_ALERT_TYPE "ok" -#define GREETING_MESSAGE_ALERT_STRING \ -"\ -Welcome to NX from the NoMachine team. We really\n\ -hope you will enjoy this wonderful software as much\n\ -as we had fun making it ;-).\n\ -" - -/* - * These alerts are intended to notify the user - * of the reason why the agent failed to resume - * the session. - */ - -#define START_RESUME_SESSION_ALERT 16 -#define START_RESUME_SESSION_ALERT_TYPE "ok" -#define START_RESUME_SESSION_ALERT_STRING \ -"\ -You appear to run your NX session across a slow network\n\ -connection. Resuming the session may require some time.\n\ -Please wait.\ -" - -#define FAILED_RESUME_DISPLAY_ALERT 17 -#define FAILED_RESUME_DISPLAY_ALERT_TYPE "error" -#define FAILED_RESUME_DISPLAY_ALERT_STRING \ -"\ -Failed to open the display. Can't resume the NX\n\ -session on this display.\n\ -" - -#define FAILED_RESUME_DISPLAY_BROKEN_ALERT 18 -#define FAILED_RESUME_DISPLAY_BROKEN_TYPE "error" -#define FAILED_RESUME_DISPLAY_BROKEN_STRING \ -"\ -The display connection was broken while trying to\n\ -resume the session. Please, check your network\n\ -connection and try again.\n\ -" - -#define FAILED_RESUME_VISUALS_ALERT 19 -#define FAILED_RESUME_VISUALS_ALERT_TYPE "error" -#define FAILED_RESUME_VISUALS_ALERT_STRING \ -"\ -Failed to restore all the required visuals.\n\ -Can't resume the NX session on this display.\n\ -" - -#define FAILED_RESUME_COLORMAPS_ALERT 20 -#define FAILED_RESUME_COLORMAPS_ALERT_TYPE "error" -#define FAILED_RESUME_COLORMAPS_ALERT_STRING \ -"\ -The number of available colormaps is different\n\ -on the new display. Can't resume the NX session\n\ -on this display.\n\ -" - -#define FAILED_RESUME_PIXMAPS_ALERT 21 -#define FAILED_RESUME_PIXMAPS_ALERT_TYPE "error" -#define FAILED_RESUME_PIXMAPS_ALERT_STRING \ -"\ -Failed to restore all the required pixmap formats.\n\ -Can't resume the NX session on this display.\n\ -" - -#define FAILED_RESUME_DEPTHS_ALERT 22 -#define FAILED_RESUME_DEPTHS_ALERT_TYPE "error" -#define FAILED_RESUME_DEPTHS_ALERT_STRING \ -"\ -Failed to restore all the required screen depths.\n\ -Can't resume the NX session on this display.\n\ -" - -#define FAILED_RESUME_RENDER_ALERT 23 -#define FAILED_RESUME_RENDER_ALERT_TYPE "error" -#define FAILED_RESUME_RENDER_ALERT_STRING \ -"\ -The render extension is missing or an incompatible\n\ -version was detected on your X server. Can't resume\n\ -the NX session on this display.\n\ -" - -#define FAILED_RESUME_FONTS_ALERT 24 -#define FAILED_RESUME_FONTS_ALERT_TYPE "error" -#define FAILED_RESUME_FONTS_ALERT_STRING \ -"\ -One or more of the fonts that are in use by the\n\ -session are missing. Can't resume the NX session\n\ -on this display.\n\ -" - -#define ABORT_PROXY_NEGOTIATION_ALERT 62 -#define ABORT_PROXY_NEGOTIATION_ALERT_TYPE "ok" -#define ABORT_PROXY_NEGOTIATION_ALERT_STRING \ -"\ -The remote proxy closed the connection while negotiating\n\ -the session. This may be due to the wrong authentication\n\ -credentials passed to the server.\n\ -" - -#define ABORT_PROXY_SHUTDOWN_ALERT 64 -#define ABORT_PROXY_SHUTDOWN_ALERT_TYPE "ok" -#define ABORT_PROXY_SHUTDOWN_ALERT_STRING \ -"\ -No response received from the remote proxy while\n\ -waiting for the session shutdown.\n\ -" - -#define FAILED_XDMCP_CONNECTION_ALERT 65 -#define FAILED_XDMCP_CONNECTION_ALERT_TYPE "ok" -#define FAILED_XDMCP_CONNECTION_ALERT_STRING \ -"\ -The XDM host that was contacted by the NX server doesn't\n\ -seem to be able to start the session. Please check your\n\ -server configuration.\n\ -" - -/* - * Used to handle the backward compatibility. - * Update the numbers if you add a new alert. - */ - -#define LAST_PROTO_STEP_6_ALERT 63 -#define LAST_PROTO_STEP_7_ALERT 65 - -#endif /* NXalert_H */ diff --git a/nxcomp/NXmitshm.h b/nxcomp/NXmitshm.h deleted file mode 100644 index 939d488fb..000000000 --- a/nxcomp/NXmitshm.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef NXmitshm_H -#define NXmitshm_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Import opcodes from - * to get rid of weird dependencies from other - * headers of X environment. - */ - -#define X_ShmQueryVersion 0 -#define X_ShmAttach 1 -#define X_ShmDetach 2 -#define X_ShmPutImage 3 -#define X_ShmGetImage 4 -#define X_ShmCreatePixmap 5 - -#define ShmCompletion 0 -#define ShmNumberEvents (ShmCompletion + 1) - -#define BadShmSeg 0 -#define ShmNumberErrors (BadShmSeg + 1) - -#ifdef __cplusplus -} -#endif - -#endif /* NXmitshm_H */ diff --git a/nxcomp/NXpack.h b/nxcomp/NXpack.h deleted file mode 100644 index 3eade6855..000000000 --- a/nxcomp/NXpack.h +++ /dev/null @@ -1,141 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef NXpack_H -#define NXpack_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define MASK_METHOD_LIMIT 10 - -#define NO_MASK 0 - -#define MASK_8_COLORS 1 -#define MASK_64_COLORS 2 -#define MASK_256_COLORS 3 -#define MASK_512_COLORS 4 -#define MASK_4K_COLORS 5 -#define MASK_32K_COLORS 6 -#define MASK_64K_COLORS 7 -#define MASK_256K_COLORS 8 -#define MASK_2M_COLORS 9 -#define MASK_16M_COLORS 10 - -#define PACK_METHOD_LIMIT 128 - -#define NO_PACK 0 - -#define PACK_MASKED_8_COLORS 1 -#define PACK_MASKED_64_COLORS 2 -#define PACK_MASKED_256_COLORS 3 -#define PACK_MASKED_512_COLORS 4 -#define PACK_MASKED_4K_COLORS 5 -#define PACK_MASKED_32K_COLORS 6 -#define PACK_MASKED_64K_COLORS 7 -#define PACK_MASKED_256K_COLORS 8 -#define PACK_MASKED_2M_COLORS 9 -#define PACK_MASKED_16M_COLORS 10 - -#define PACK_RAW_8_BITS 3 -#define PACK_RAW_16_BITS 7 -#define PACK_RAW_24_BITS 10 - -#define PACK_COLORMAP_256_COLORS 11 - -#define PACK_JPEG_8_COLORS 26 -#define PACK_JPEG_64_COLORS 27 -#define PACK_JPEG_256_COLORS 28 -#define PACK_JPEG_512_COLORS 29 -#define PACK_JPEG_4K_COLORS 30 -#define PACK_JPEG_32K_COLORS 31 -#define PACK_JPEG_64K_COLORS 32 -#define PACK_JPEG_256K_COLORS 33 -#define PACK_JPEG_2M_COLORS 34 -#define PACK_JPEG_16M_COLORS 35 - -#define PACK_PNG_8_COLORS 37 -#define PACK_PNG_64_COLORS 38 -#define PACK_PNG_256_COLORS 39 -#define PACK_PNG_512_COLORS 40 -#define PACK_PNG_4K_COLORS 41 -#define PACK_PNG_32K_COLORS 42 -#define PACK_PNG_64K_COLORS 43 -#define PACK_PNG_256K_COLORS 44 -#define PACK_PNG_2M_COLORS 45 -#define PACK_PNG_16M_COLORS 46 - -#define PACK_RGB_16M_COLORS 63 -#define PACK_RLE_16M_COLORS 64 - -#define PACK_ALPHA 65 -#define PACK_COLORMAP 66 - -#define PACK_BITMAP_16M_COLORS 67 - -/* - * Not really pack methods. These values - * allow dynamic selection of the pack - * method by the agent. - */ - -#define PACK_NONE 0 -#define PACK_LOSSY 253 -#define PACK_LOSSLESS 254 -#define PACK_ADAPTIVE 255 - -/* - * Reduce the number of colors in the - * image by applying a mask. - */ - -typedef struct -{ - unsigned int color_mask; - unsigned int correction_mask; - unsigned int white_threshold; - unsigned int black_threshold; - -} ColorMask; - -extern const ColorMask Mask8TrueColor; -extern const ColorMask Mask64TrueColor; -extern const ColorMask Mask512TrueColor; -extern const ColorMask Mask4KTrueColor; -extern const ColorMask Mask32KTrueColor; -extern const ColorMask Mask256KTrueColor; -extern const ColorMask Mask2MTrueColor; -extern const ColorMask Mask16MTrueColor; - -const ColorMask *MethodColorMask(unsigned int method); - -int MethodBitsPerPixel(unsigned int method); - -#ifdef __cplusplus -} -#endif - -#endif /* NXpack_H */ diff --git a/nxcomp/NXproto.h b/nxcomp/NXproto.h deleted file mode 100644 index 7b988bdbf..000000000 --- a/nxcomp/NXproto.h +++ /dev/null @@ -1,447 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef NXproto_H -#define NXproto_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -/* - * Force the size to match the wire protocol. - */ - -#define Drawable CARD32 -#define GContext CARD32 - -#define sz_xNXGetControlParametersReq 4 -#define sz_xNXGetCleanupParametersReq 4 -#define sz_xNXGetImageParametersReq 4 -#define sz_xNXGetUnpackParametersReq 8 -#define sz_xNXGetShmemParametersReq 16 -#define sz_xNXGetFontParametersReq 4 -#define sz_xNXSetExposeParametersReq 8 -#define sz_xNXSetCacheParametersReq 8 -#define sz_xNXStartSplitReq 8 -#define sz_xNXEndSplitReq 4 -#define sz_xNXCommitSplitReq 12 -#define sz_xNXSetUnpackGeometryReq 24 -#define sz_xNXSetUnpackColormapReq 16 -#define sz_xNXSetUnpackAlphaReq 16 -#define sz_xNXPutPackedImageReq 40 -#define sz_xNXFreeUnpackReq 4 -#define sz_xNXFinishSplitReq 4 -#define sz_xNXAbortSplitReq 4 -#define sz_xNXFreeSplitReq 4 - -#define sz_xGetControlParametersReply 32 -#define sz_xGetCleanupParametersReply 32 -#define sz_xGetImageParametersReply 32 -#define sz_xGetUnpackParametersReply 32 -#define sz_xGetShmemParametersReply 32 - -#define LINK_TYPE_LIMIT 5 - -#define LINK_TYPE_NONE 0 -#define LINK_TYPE_MODEM 1 -#define LINK_TYPE_ISDN 2 -#define LINK_TYPE_ADSL 3 -#define LINK_TYPE_WAN 4 -#define LINK_TYPE_LAN 5 - -/* - * NX Replies. - */ - -/* - * The following reply has 4 new boolean - * fields in the last protocol version. - */ - -typedef struct _NXGetControlParametersReply { - BYTE type; /* Is X_Reply. */ - CARD8 linkType; - CARD16 sequenceNumber B16; - CARD32 length B32; /* Is 0. */ - CARD8 localMajor; - CARD8 localMinor; - CARD8 localPatch; - CARD8 remoteMajor; - CARD8 remoteMinor; - CARD8 remotePatch; - CARD16 splitTimeout B16; - CARD16 motionTimeout B16; - CARD8 splitMode; - CARD8 pad1; - CARD32 splitSize B32; - CARD8 packMethod; - CARD8 packQuality; - CARD8 dataLevel; - CARD8 streamLevel; - CARD8 deltaLevel; - CARD8 loadCache; - CARD8 saveCache; - CARD8 startupCache; -} xNXGetControlParametersReply; - -typedef struct _NXGetCleanupParametersReply { - BYTE type; /* Is X_Reply. */ - BYTE pad; - CARD16 sequenceNumber B16; - CARD32 length B32; /* Is 0. */ - BOOL cleanGet; - BOOL cleanAlloc; - BOOL cleanFlush; - BOOL cleanSend; - BOOL cleanImages; - BYTE pad1, pad2, pad3; - CARD32 pad4 B32; - CARD32 pad5 B32; - CARD32 pad6 B32; - CARD32 pad7 B32; -} xNXGetCleanupParametersReply; - -typedef struct _NXGetImageParametersReply { - BYTE type; /* Is X_Reply. */ - BYTE pad; - CARD16 sequenceNumber B16; - CARD32 length B32; /* Is 0. */ - BOOL imageSplit; - BOOL imageMask; - BOOL imageFrame; - CARD8 imageMaskMethod; - CARD8 imageSplitMethod; - BYTE pad1, pad2, pad3; - CARD32 pad4 B32; - CARD32 pad5 B32; - CARD32 pad6 B32; - CARD32 pad7 B32; -} xNXGetImageParametersReply; - -/* - * Data is made of PACK_METHOD_LIMIT values of - * type BOOL telling which unpack capabilities - * are implemented in proxy. - */ - -typedef struct _NXGetUnpackParametersReply { - BYTE type; /* Is X_Reply. */ - BYTE pad; - CARD16 sequenceNumber B16; - CARD32 length B32; /* Is PACK_METHOD_LIMIT / 4 from NXpack.h. */ - CARD8 entries; /* Is PACK_METHOD_LIMIT. */ - BYTE pad1, pad2, pad3; - CARD32 pad4 B32; - CARD32 pad5 B32; - CARD32 pad6 B32; - CARD32 pad7 B32; - CARD32 pad8 B32; -} xNXGetUnpackParametersReply; - -typedef struct _NXGetShmemParametersReply { - BYTE type; /* Is X_Reply. */ - CARD8 stage; /* As in the corresponding request. */ - CARD16 sequenceNumber B16; - CARD32 length B32; /* Is 0. */ - BOOL clientEnabled; /* SHM on path agent to proxy. */ - BOOL serverEnabled; /* SHM on path proxy to X server. */ - BYTE pad1, pad2; /* Previous values can be checked */ - CARD32 clientSize B32; /* at end of stage 2. */ - CARD32 serverSize B32; - CARD32 pad3 B32; - CARD32 pad4 B32; - CARD32 pad5 B32; -} xNXGetShmemParametersReply; - -typedef struct _NXGetFontParametersReply { - BYTE type; /* Is X_Reply. */ - BYTE pad1; - CARD16 sequenceNumber B16; - CARD32 length B32; /* Is length of path string + 1 / 4. */ - CARD32 pad2 B32; - CARD32 pad3 B32; - CARD32 pad4 B32; - CARD32 pad5 B32; - CARD32 pad6 B32; - CARD32 pad7 B32; -} xNXGetFontParametersReply; - -/* - * NX Requests. - */ - -typedef struct _NXGetControlParametersReq { - CARD8 reqType; - BYTE pad; - CARD16 length B16; -} xNXGetControlParametersReq; - -typedef struct _NXGetCleanupParametersReq { - CARD8 reqType; - BYTE pad; - CARD16 length B16; -} xNXGetCleanupParametersReq; - -typedef struct _NXGetImageParametersReq { - CARD8 reqType; - BYTE pad; - CARD16 length B16; -} xNXGetImageParametersReq; - -typedef struct _NXGetUnpackParametersReq { - CARD8 reqType; - BYTE pad; - CARD16 length B16; - CARD8 entries; - BYTE pad1, pad2, pad3; -} xNXGetUnpackParametersReq; - -typedef struct _NXGetShmemParametersReq { - CARD8 reqType; - CARD8 stage; /* It is between 0 and 2. */ - CARD16 length B16; - BOOL enableClient; /* X client side support is */ - BOOL enableServer; /* not implemented yet. */ - BYTE pad1, pad2; - CARD32 clientSegment; /* XID identifying the shared */ - CARD32 serverSegment; /* memory segments. */ -} xNXGetShmemParametersReq; - -typedef struct _NXGetFontParametersReq { - CARD8 reqType; - CARD8 pad; - CARD16 length B16; -} xNXGetFontParametersReq; - -/* - * The available split modes. - */ - -#define NXSplitModeDefault 0 -#define NXSplitModeAsync 1 -#define NXSplitModeSync 2 - -typedef struct _NXStartSplitReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; - CARD8 mode; - BYTE pad1, pad2, pad3; -} xNXStartSplitReq; - -typedef struct _NXEndSplitReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; -} xNXEndSplitReq; - -typedef struct _NXCommitSplitReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; - CARD8 propagate; - CARD8 request; - BYTE pad1, pad2; - CARD32 position B32; -} xNXCommitSplitReq; - -typedef struct _NXFinishSplitReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; -} xNXFinishSplitReq; - -typedef struct _NXAbortSplitReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; -} xNXAbortSplitReq; - -typedef struct _NXFreeSplitReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; -} xNXFreeSplitReq; - -typedef struct _NXSetExposeParametersReq { - CARD8 reqType; - BYTE pad; - CARD16 length B16; - BOOL expose; - BOOL graphicsExpose; - BOOL noExpose; - BYTE pad1; -} xNXSetExposeParametersReq; - -typedef struct _NXSetCacheParametersReq { - CARD8 reqType; - BYTE pad; - CARD16 length B16; - BOOL enableCache; - BOOL enableSplit; - BOOL enableSave; - BOOL enableLoad; -} xNXSetCacheParametersReq; - -typedef struct _NXSetUnpackGeometryReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; - CARD8 depth1Bpp; - CARD8 depth4Bpp; - CARD8 depth8Bpp; - CARD8 depth16Bpp; - CARD8 depth24Bpp; - CARD8 depth32Bpp; - BYTE pad1, pad2; - CARD32 redMask B32; - CARD32 greenMask B32; - CARD32 blueMask B32; -} xNXSetUnpackGeometryReq; - -typedef struct _NXSetUnpackColormapReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; - CARD8 method; - BYTE pad1, pad2, pad3; - CARD32 srcLength B32; - CARD32 dstLength B32; -} xNXSetUnpackColormapReq; - -typedef struct _NXSetUnpackAlphaReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; - CARD8 method; - BYTE pad1, pad2, pad3; - CARD32 srcLength B32; - CARD32 dstLength B32; -} xNXSetUnpackAlphaReq; - -typedef struct _NXPutPackedImageReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; - Drawable drawable B32; - GContext gc B32; - CARD8 method; - CARD8 format; - CARD8 srcDepth; - CARD8 dstDepth; - CARD32 srcLength B32; - CARD32 dstLength B32; - INT16 srcX B16, srcY B16; - CARD16 srcWidth B16, srcHeight B16; - INT16 dstX B16, dstY B16; - CARD16 dstWidth B16, dstHeight B16; -} xNXPutPackedImageReq; - -typedef struct _NXFreeUnpackReq { - CARD8 reqType; - CARD8 resource; - CARD16 length B16; -} xNXFreeUnpackReq; - -/* - * The X_NXSplitData and X_NXSplitEvent opcodes - * are used internally and are ignored if coming - * from the agent. - */ - -#define X_NXInternalGenericData 0 -#define X_NXInternalGenericReply 1 -#define X_NXInternalGenericRequest 255 - -#define X_NXInternalShapeExtension 128 -#define X_NXInternalRenderExtension 129 - -#define X_NXFirstOpcode 230 -#define X_NXLastOpcode 252 - -#define X_NXGetControlParameters 230 -#define X_NXGetCleanupParameters 231 -#define X_NXGetImageParameters 232 -#define X_NXGetUnpackParameters 233 -#define X_NXStartSplit 234 -#define X_NXEndSplit 235 -#define X_NXSplitData 236 -#define X_NXCommitSplit 237 -#define X_NXSetExposeParameters 240 -#define X_NXSetUnpackGeometry 241 -#define X_NXSetUnpackColormap 242 -#define X_NXPutPackedImage 243 -#define X_NXSplitEvent 244 -#define X_NXGetShmemParameters 245 -#define X_NXSetUnpackAlpha 246 -#define X_NXFreeUnpack 247 -#define X_NXFinishSplit 248 -#define X_NXAbortSplit 249 -#define X_NXFreeSplit 250 -#define X_NXGetFontParameters 251 -#define X_NXSetCacheParameters 252 - -/* - * The following events are received by the agent - * in the form of a ClientMessage with the value - * 0 in fields atom and window. The format is - * always 32. Event specific data starts at byte - * offset 12. - * - * These events are sent by the NX transport to - * notify the agent about the result of a split - * operation. - */ - -#define NXNoSplitNotify 1 -#define NXStartSplitNotify 2 -#define NXCommitSplitNotify 3 -#define NXEndSplitNotify 4 -#define NXEmptySplitNotify 5 - -/* - * Notifications of collect events. These events - * don't come from the NX transport but are put - * back in client's event queue by NXlib. - */ - -#define NXCollectImageNotify 8 -#define NXCollectPropertyNotify 9 -#define NXCollectGrabPointerNotify 10 -#define NXCollectInputFocusNotify 11 - -#undef Drawable -#undef GContext - -#ifdef __cplusplus -} -#endif - -#endif /* NXproto_H */ diff --git a/nxcomp/NXrender.h b/nxcomp/NXrender.h deleted file mode 100644 index 280715833..000000000 --- a/nxcomp/NXrender.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef NXrender_H -#define NXrender_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Import this from - * to compile under old XFree86 distributions - * when render extension was not present yet. - */ - -#define X_RenderQueryVersion 0 -#define X_RenderQueryPictFormats 1 -#define X_RenderQueryPictIndexValues 2 -#define X_RenderQueryDithers 3 -#define X_RenderCreatePicture 4 -#define X_RenderChangePicture 5 -#define X_RenderSetPictureClipRectangles 6 -#define X_RenderFreePicture 7 -#define X_RenderComposite 8 -#define X_RenderScale 9 -#define X_RenderTrapezoids 10 -#define X_RenderTriangles 11 -#define X_RenderTriStrip 12 -#define X_RenderTriFan 13 -#define X_RenderColorTrapezoids 14 -#define X_RenderColorTriangles 15 -#define X_RenderTransform 16 -#define X_RenderCreateGlyphSet 17 -#define X_RenderReferenceGlyphSet 18 -#define X_RenderFreeGlyphSet 19 -#define X_RenderAddGlyphs 20 -#define X_RenderAddGlyphsFromPicture 21 -#define X_RenderFreeGlyphs 22 -#define X_RenderCompositeGlyphs8 23 -#define X_RenderCompositeGlyphs16 24 -#define X_RenderCompositeGlyphs32 25 -#define X_RenderFillRectangles 26 -/* 0.5 */ -#define X_RenderCreateCursor 27 -/* 0.6 */ -#define X_RenderSetPictureTransform 28 -#define X_RenderQueryFilters 29 -#define X_RenderSetPictureFilter 30 -#define X_RenderCreateAnimCursor 31 - -#ifdef __cplusplus -} -#endif - -#endif /* NXrender_H */ diff --git a/nxcomp/NXvars.h b/nxcomp/NXvars.h deleted file mode 100644 index f514000d7..000000000 --- a/nxcomp/NXvars.h +++ /dev/null @@ -1,201 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef NXvars_H -#define NXvars_H - -/* - * This can be included by the proxy or another - * layer that doesn't use Xlib. - */ - -#if !defined(_XLIB_H_) && !defined(_XKBSRV_H_) - -#define NeedFunctionPrototypes 1 - -#define Display void - -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Display flush policies. - */ - -#define NXPolicyImmediate 1 -#define NXPolicyDeferred 2 - -/* - * Type of flush. - */ - -#define NXFlushBuffer 0 -#define NXFlushLink 1 - -/* - * Type of statistics. - */ - -#define NXStatisticsPartial 0 -#define NXStatisticsTotal 1 - -/* - * Reason why the display is blocking. - */ - -#define NXBlockRead 1 -#define NXBlockWrite 2 - -/* - * Set if the client is interested in ignoring - * the display error and continue with the exe- - * cution of the program. By default the usual - * Xlib behaviour is gotten, and the library - * will call an exit(). - */ - -extern int _NXHandleDisplayError; - -/* - * The function below is called whenever Xlib is - * going to perform an I/O operation. The funct- - * ion can be redefined to include additional - * checks aimed at detecting if the display needs - * to be closed, for example because of an event - * or a signal mandating the end of the session. - * In this way the client program can regain the - * control before Xlib blocks waiting for input - * from the network. - */ - -typedef int (*NXDisplayErrorPredicate)( -#if NeedFunctionPrototypes - Display* /* display */, - int /* reason */ -#endif -); - -extern NXDisplayErrorPredicate _NXDisplayErrorFunction; - -/* - * This is called when Xlib is going to block - * waiting for the display to become readable or - * writable. The client can use the hook to run - * any arbitrary operation that may require some - * time to complete. The user should not try to - * read or write to the display inside the call- - * back routine. - */ - -typedef void (*NXDisplayBlockHandler)( -#if NeedFunctionPrototypes - Display* /* display */, - int /* reason */ -#endif -); - -extern NXDisplayBlockHandler _NXDisplayBlockFunction; - -/* - * Used to notify the program when more data - * is written to the socket. - */ - -typedef void (*NXDisplayWriteHandler)( -#if NeedFunctionPrototypes - Display* /* display */, - int /* length */ -#endif -); - -extern NXDisplayWriteHandler _NXDisplayWriteFunction; - -/* - * This callback is used to notify the agent - * that the proxy link has been flushed. - */ - -typedef void (*NXDisplayFlushHandler)( -#if NeedFunctionPrototypes - Display* /* display */, - int /* length */ -#endif -); - -extern NXDisplayFlushHandler _NXDisplayFlushFunction; - -/* - * Used by the NX transport to get an arbitrary - * string to add to its protocol statistics. - */ - -typedef void (*NXDisplayStatisticsHandler)( -#if NeedFunctionPrototypes - Display* /* display */, - char* /* buffer */, - int /* size */ -#endif -); - -extern NXDisplayStatisticsHandler _NXDisplayStatisticsFunction; - -/* - * Let users redefine the function printing an - * error message in the case of a out-of-order - * sequence number. - */ - -typedef void (*NXLostSequenceHandler)( -#if NeedFunctionPrototypes - Display* /* display */, - unsigned long /* newseq */, - unsigned long /* lastseq */, - unsigned int /* type */ -#endif -); - -extern NXLostSequenceHandler _NXLostSequenceFunction; - -/* - * Let the X server run the children processes - * (as for example the keyboard initialization - * utilities) by using the native system libra- - * ries, instead of the libraries shipped with - * the NX environment. If set, the Popen() in - * the X server will remove the LD_LIBRARY_PATH - * setting from the environment before calling - * the execl() function in the child process. - */ - -extern int _NXUnsetLibraryPath; - -#ifdef __cplusplus -} -#endif - -#endif /* NXvars_H */ diff --git a/nxcomp/OpcodeCache.h b/nxcomp/OpcodeCache.h deleted file mode 100644 index e07a1b997..000000000 --- a/nxcomp/OpcodeCache.h +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef OpcodeCache_H -#define OpcodeCache_H - -#include "CharCache.h" - -class OpcodeCache -{ - friend class EncodeBuffer; - friend class DecodeBuffer; - - public: - - OpcodeCache() - { - slot_ = 0; - } - - ~OpcodeCache() - { - } - - private: - - CharCache base_[256]; - unsigned char slot_; -}; - -#endif /* OpcodeCache_H */ diff --git a/nxcomp/OpcodeStore.cpp b/nxcomp/OpcodeStore.cpp deleted file mode 100644 index 66a425d53..000000000 --- a/nxcomp/OpcodeStore.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "OpcodeStore.h" - -OpcodeStore::OpcodeStore() -{ - // - // Assign values of the specific - // NX opcodes. - // - - getControlParameters = X_NXGetControlParameters; - getCleanupParameters = X_NXGetCleanupParameters; - getImageParameters = X_NXGetImageParameters; - getUnpackParameters = X_NXGetUnpackParameters; - getShmemParameters = X_NXGetShmemParameters; - getFontParameters = X_NXGetFontParameters; - - startSplit = X_NXStartSplit; - endSplit = X_NXEndSplit; - commitSplit = X_NXCommitSplit; - finishSplit = X_NXFinishSplit; - abortSplit = X_NXAbortSplit; - - splitData = X_NXSplitData; - splitEvent = X_NXSplitEvent; - - setCacheParameters = X_NXSetCacheParameters; - setExposeParameters = X_NXSetExposeParameters; - - setUnpackGeometry = X_NXSetUnpackGeometry; - setUnpackColormap = X_NXSetUnpackColormap; - setUnpackAlpha = X_NXSetUnpackAlpha; - - putPackedImage = X_NXPutPackedImage; - - freeUnpack = X_NXFreeUnpack; - freeSplit = X_NXFreeSplit; - - // - // These values must be fetched - // from the X server. - // - - shapeExtension = 0; - renderExtension = 0; - - // - // Events sent as ClientMessage. - // - - noSplitNotify = NXNoSplitNotify; - startSplitNotify = NXStartSplitNotify; - commitSplitNotify = NXCommitSplitNotify; - endSplitNotify = NXEndSplitNotify; - emptySplitNotify = NXEmptySplitNotify; -} - -OpcodeStore::~OpcodeStore() -{ -} diff --git a/nxcomp/OpcodeStore.h b/nxcomp/OpcodeStore.h deleted file mode 100644 index d041ed4b8..000000000 --- a/nxcomp/OpcodeStore.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef OpcodeStore_H -#define OpcodeStore_H - -#include "NXproto.h" - -class OpcodeStore -{ - public: - - OpcodeStore(); - - ~OpcodeStore(); - - // - // Map NX protocol messages. At the moment mapping is hard- - // coded. Opcodes should be instead agreed with the proxied - // X server (by excluding all opcodes used for extensions) - // and exported by the proxy class to channels. - // - // Some toolkits query the server only once for extensions' - // opcodes and share the same settings across all channels. - // This could be a problem as channels needed to monitor the - // traffic to find out the extensions' opcodes themselves, - // so it is important that proxy passes an instance of this - // class to new channels. - // - - unsigned char getControlParameters; - unsigned char getCleanupParameters; - unsigned char getImageParameters; - unsigned char getUnpackParameters; - unsigned char getShmemParameters; - unsigned char getFontParameters; - - unsigned char startSplit; - unsigned char endSplit; - unsigned char commitSplit; - unsigned char finishSplit; - unsigned char abortSplit; - - unsigned char splitData; - unsigned char splitEvent; - - unsigned char setCacheParameters; - unsigned char setExposeParameters; - - unsigned char setUnpackGeometry; - unsigned char setUnpackColormap; - unsigned char setUnpackAlpha; - - unsigned char putPackedImage; - - unsigned char freeUnpack; - unsigned char freeSplit; - - unsigned char shapeExtension; - unsigned char renderExtension; - - unsigned char noSplitNotify; - unsigned char startSplitNotify; - unsigned char commitSplitNotify; - unsigned char endSplitNotify; - unsigned char emptySplitNotify; -}; - -#endif /* OpcodeStore_H */ diff --git a/nxcomp/Pack.c b/nxcomp/Pack.c deleted file mode 100644 index 97fb93b5f..000000000 --- a/nxcomp/Pack.c +++ /dev/null @@ -1,180 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include "NXpack.h" - -const ColorMask Mask8TrueColor = { 128, 63, 240, 7 }; -const ColorMask Mask64TrueColor = { 192, 7, 240, 4 }; -const ColorMask Mask256TrueColor = { 255, 0, 255, 0 }; -const ColorMask Mask512TrueColor = { 224, 5, 240, 4 }; -const ColorMask Mask4KTrueColor = { 240, 4, 240, 2 }; -const ColorMask Mask32KTrueColor = { 248, 3, 248, 2 }; -const ColorMask Mask64KTrueColor = { 255, 0, 255, 0 }; -const ColorMask Mask256KTrueColor = { 252, 1, 252, 1 }; -const ColorMask Mask2MTrueColor = { 255, 0, 254, 1 }; -const ColorMask Mask16MTrueColor = { 255, 0, 255, 0 }; - -const ColorMask *MethodColorMask(unsigned int method) -{ - switch (method) - { - case MASK_8_COLORS: - { - return &Mask8TrueColor; - } - case MASK_64_COLORS: - { - return &Mask64TrueColor; - } - case MASK_256_COLORS: - { - return &Mask256TrueColor; - } - case MASK_512_COLORS: - { - return &Mask512TrueColor; - } - case MASK_4K_COLORS: - { - return &Mask4KTrueColor; - } - case MASK_32K_COLORS: - { - return &Mask32KTrueColor; - } - case MASK_64K_COLORS: - { - return &Mask64KTrueColor; - } - case MASK_256K_COLORS: - { - return &Mask256KTrueColor; - } - case MASK_2M_COLORS: - { - return &Mask2MTrueColor; - } - case MASK_16M_COLORS: - { - return &Mask16MTrueColor; - } - default: - { - return NULL; - } - } -} - -int MethodBitsPerPixel(unsigned int method) -{ - switch (method) - { - case PACK_MASKED_8_COLORS: - case PACK_JPEG_8_COLORS: - case PACK_PNG_8_COLORS: - { - return 8; - } - case PACK_MASKED_64_COLORS: - case PACK_JPEG_64_COLORS: - case PACK_PNG_64_COLORS: - { - return 8; - } - case PACK_MASKED_256_COLORS: - case PACK_JPEG_256_COLORS: - case PACK_PNG_256_COLORS: - { - return 8; - } - case PACK_MASKED_512_COLORS: - case PACK_JPEG_512_COLORS: - case PACK_PNG_512_COLORS: - { - return 16; - } - case PACK_MASKED_4K_COLORS: - case PACK_JPEG_4K_COLORS: - case PACK_PNG_4K_COLORS: - { - return 16; - } - case PACK_MASKED_32K_COLORS: - case PACK_JPEG_32K_COLORS: - case PACK_PNG_32K_COLORS: - { - return 16; - } - case PACK_MASKED_64K_COLORS: - case PACK_JPEG_64K_COLORS: - case PACK_PNG_64K_COLORS: - { - return 16; - } - case PACK_MASKED_256K_COLORS: - case PACK_JPEG_256K_COLORS: - case PACK_PNG_256K_COLORS: - { - return 24; - } - case PACK_MASKED_2M_COLORS: - case PACK_JPEG_2M_COLORS: - case PACK_PNG_2M_COLORS: - { - return 24; - } - case PACK_MASKED_16M_COLORS: - case PACK_JPEG_16M_COLORS: - case PACK_PNG_16M_COLORS: - { - return 24; - } - case PACK_BITMAP_16M_COLORS: - case PACK_RGB_16M_COLORS: - case PACK_RLE_16M_COLORS: - { - return 24; - } - default: - { - return 0; - } - } -} - -#ifdef __cplusplus -} -#endif diff --git a/nxcomp/Pgn.cpp b/nxcomp/Pgn.cpp deleted file mode 100644 index 17e1702d4..000000000 --- a/nxcomp/Pgn.cpp +++ /dev/null @@ -1,805 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// This file obviously supports PNG -// decompression. It was renamed to -// avoid name clashes on Windows. -// - -#include - -#ifdef ANDROID -#include -#endif -#include -#include -#include - -#include "Unpack.h" -#include "Pgn.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#define RGB24_TO_PIXEL(bpp,r,g,b) \ - ((((CARD##bpp)(r) & 0xFF) * srcRedMax2 + 127) / 255 \ - << srcRedShift2 | \ - (((CARD##bpp)(g) & 0xFF) * srcGreenMax2 + 127) / 255 \ - << srcGreenShift2 | \ - (((CARD##bpp)(b) & 0xFF) * srcBlueMax2 + 127) / 255 \ - << srcBlueShift2) - -#define RGB24_TO_PIXEL32(r,g,b) \ - (((CARD32)(r) & 0xFF) << srcRedShift2 | \ - ((CARD32)(g) & 0xFF) << srcGreenShift2 | \ - ((CARD32)(b) & 0xFF) << srcBlueShift2) - -// -// Functions from Unpack.cpp -// - -extern int Unpack32To32(const T_colormask *colormask, const unsigned int *data, - unsigned int *out, unsigned int *end); - -extern int Unpack24To24(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -extern int Unpack16To16(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -// -// Local functions used for the png decompression. -// - -static int DecompressPng16(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, - int byteOrder); - -static int DecompressPng24(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, - int byteOrder); - -static int DecompressPng32(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, - int byteOrder); - -static void PngReadData(png_structp png_ptr, png_bytep data, png_size_t length); - -// -// Colormap stuff. -// - -CARD16 srcRedMax2, srcGreenMax2, srcBlueMax2; -CARD8 srcRedShift2, srcGreenShift2, srcBlueShift2; - -// -// Attributes used for the png decompression. -// - -static char *tmpBuf; -static int tmpBufSize = 0; -static int streamPos; - -int UnpackPng(T_geometry *geometry, unsigned char method, unsigned char *srcData, - int srcSize, int dstBpp, int dstWidth, int dstHeight, - unsigned char *dstData, int dstSize) -{ - int byteOrder = geometry -> image_byte_order; - - // - // Check if data is coming from a failed unsplit. - // - - if (srcSize < 2 || (srcData[0] == SPLIT_PATTERN && - srcData[1] == SPLIT_PATTERN)) - { - #ifdef WARNING - *logofs << "UnpackPng: WARNING! Skipping unpack of dummy data.\n" - << logofs_flush; - #endif - - return -1; - } - - #ifdef DEBUG - *logofs << "UnpackPng: Decompressing image with " - << "srcSize " << srcSize << " and bpp " - << dstBpp << ".\n" << logofs_flush; - #endif - - srcRedShift2 = ffs(geometry -> red_mask) - 1; - srcGreenShift2 = ffs(geometry -> green_mask) - 1; - srcBlueShift2 = ffs(geometry -> blue_mask) - 1; - srcRedMax2 = geometry -> red_mask >> srcRedShift2; - srcGreenMax2 = geometry -> green_mask >> srcGreenShift2; - srcBlueMax2 = geometry -> blue_mask >> srcBlueShift2; - - // - // Make enough space in the temporary - // buffer to have one complete row of - // the image with 3 bytes per pixel. - // - - tmpBufSize = dstWidth * 3; - tmpBuf = new char [tmpBufSize]; - - if (tmpBuf == NULL) - { - #ifdef PANIC - *logofs << "UnpackPng: PANIC! Cannot allocate " - << dstWidth * 3 << " bytes for PNG " - << "decompressed data.\n" << logofs_flush; - #endif - - delete [] tmpBuf; - - return -1; - } - - int result = 1; - - switch (dstBpp) - { - case 8: - { - // - // Simply move the data from srcData to dstData - // taking into consideration the correct padding. - // - - int row; - - unsigned char * dstBuff = dstData; - unsigned char * srcBuff = srcData; - - for (row = 0; row < dstHeight; row++) - { - memcpy(dstBuff, srcBuff, dstWidth ); - - dstBuff += RoundUp4(dstWidth); - srcBuff += dstWidth; - } - } - case 16: - { - result = DecompressPng16(srcData, srcSize, dstWidth, - dstHeight, dstData, byteOrder); - break; - } - case 24: - { - result = DecompressPng24(srcData, srcSize, dstWidth, - dstHeight, dstData, byteOrder); - break; - } - case 32: - { - result = DecompressPng32(srcData, srcSize, dstWidth, - dstHeight, dstData, byteOrder); - break; - } - default: - { - #ifdef PANIC - *logofs << "UnpackPng: PANIC! Error in PNG compression. " - << " Unsupported Bpp value " << dstBpp - << " for the PNG compression" - << ".\n" << logofs_flush; - #endif - - delete [] tmpBuf; - - result = -1; - } - } - - if (result == -1) - { - delete [] tmpBuf; - - return result; - } - - // - // Apply the correction for the brightness - // - - int maskMethod; - - switch (method) - { - case PACK_PNG_8_COLORS: - { - maskMethod = MASK_8_COLORS; - - break; - } - case PACK_PNG_64_COLORS: - { - maskMethod = MASK_64_COLORS; - - break; - } - case PACK_PNG_256_COLORS: - { - maskMethod = MASK_256_COLORS; - - break; - } - case PACK_PNG_512_COLORS: - { - maskMethod = MASK_512_COLORS; - - break; - } - case PACK_PNG_4K_COLORS: - { - maskMethod = MASK_4K_COLORS; - - break; - } - case PACK_PNG_32K_COLORS: - { - maskMethod = MASK_32K_COLORS; - - break; - } - case PACK_PNG_64K_COLORS: - { - maskMethod = MASK_64K_COLORS; - - break; - } - case PACK_PNG_256K_COLORS: - { - maskMethod = MASK_256K_COLORS; - - break; - } - case PACK_PNG_2M_COLORS: - { - maskMethod = MASK_2M_COLORS; - - break; - } - case PACK_PNG_16M_COLORS: - { - maskMethod = MASK_16M_COLORS; - - break; - } - default: - { - #ifdef PANIC - *logofs << "DecompressPng16: PANIC! " - << " No matching decompression method.\n" - << logofs_flush; - #endif - - delete [] tmpBuf; - - return -1; - } - } - - const T_colormask *colorMask = MethodColorMask(maskMethod); - - unsigned char *dstBuff = dstData; - - switch (dstBpp) - { - case 16: - { - Unpack16To16(colorMask, dstBuff, dstBuff, dstBuff + dstSize); - - break; - } - case 24: - { - break; - } - case 32: - { - Unpack32To32(colorMask, (unsigned int *)dstBuff, (unsigned int *)dstBuff, - (unsigned int *)(dstBuff + dstSize)); - break; - } - default: - { - #ifdef PANIC - *logofs << "DecompressPng16: PANIC! " - << " No matching destination bits per plane.\n" - << logofs_flush; - #endif - - delete [] tmpBuf; - - return -1; - } - } - - delete [] tmpBuf; - - return 1; -} - - -// -// Functions that actually do -// the PNG decompression. -// - -int DecompressPng16(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) -{ - unsigned char *data; - unsigned int dx, dy; - - png_structp pngPtr; - png_infop infoPtr; - png_bytep rowPointers; - - - streamPos = 0; - - pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!pngPtr) - { - #ifdef PANIC - *logofs << "DecompressPng16: PANIC! " - << " Failed png_create_read_struct operation" - << ".\n" << logofs_flush; - #endif - - return -1; - } - - infoPtr = png_create_info_struct(pngPtr); - - if (!infoPtr) - { - #ifdef PANIC - *logofs << "DecompressPng16: PANIC! " - << "Failed png_create_info_struct operation" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, NULL, NULL); - - return -1; - } - - if (setjmp(png_jmpbuf(pngPtr))) - { - #ifdef PANIC - *logofs << "DecompressPng16: PANIC! " - << "Error during IO initialization" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - - return -1; - } - - png_set_read_fn(pngPtr, (void *)compressedData, PngReadData); - - if (setjmp(png_jmpbuf(pngPtr))) - { - #ifdef PANIC - *logofs << "DecompressPng16: PANIC! " - << "Error during read of PNG header" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - - return -1; - } - - png_read_info(pngPtr, infoPtr); - - if (png_get_color_type(pngPtr, infoPtr) == PNG_COLOR_TYPE_PALETTE) - { - png_set_expand(pngPtr); - } - - // - // data points to dstBuf which is - // already padded correctly for the final - // image to put - // - - data = dstBuf; - rowPointers = (png_byte *) tmpBuf; - - // - // We use setjmp() to save our context. - // The PNG library will call longjmp() - // in case of error. - // - - if (setjmp(png_jmpbuf(pngPtr))) - { - #ifdef PANIC - *logofs << "DecompressPng16: PANIC! " - << "Error during read of PNG rows" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - - return -1; - } - - unsigned long pixel; - - for (dy = 0; dy < h; dy++) - { - png_read_row(pngPtr, rowPointers, NULL); - - for (dx = 0; dx < w; dx++) - { - pixel = RGB24_TO_PIXEL(16, tmpBuf[dx*3], tmpBuf[dx*3+1], tmpBuf[dx*3+2]); - - // - // Follow the server byte order when arranging data. - // - - if (byteOrder == LSBFirst) - { - data[0] = (unsigned char) (pixel & 0xff); - data[1] = (unsigned char) ((pixel >> 8) & 0xff); - } - else - { - data[1] = (unsigned char) (pixel & 0xff); - data[0] = (unsigned char) ((pixel >> 8) & 0xff); - } - - data += 2; - } - - // - // Move pixelPtr at the beginning of the - // next line. - // - - data = data + (RoundUp4(w * 2) - w * 2); - } - - png_destroy_read_struct(&pngPtr, &infoPtr,NULL); - - #ifdef DEBUG - *logofs << "DecompressPng16: Decompression finished." - << dy << " lines handled.\n" - << logofs_flush; - #endif - - return 1; -} - -int DecompressPng24(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) -{ - static CARD8 *pixelPtr = NULL; - unsigned int dx, dy; - - png_structp pngPtr; - png_infop infoPtr; - png_bytep rowPointers; - - - streamPos = 0; - - pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!pngPtr) - { - #ifdef PANIC - *logofs << "DecompressPng24: PANIC! " - << "Failed png_create_read_struct operation" - << ".\n" << logofs_flush; - #endif - - return -1; - } - - infoPtr = png_create_info_struct(pngPtr); - - if (!infoPtr) - { - #ifdef PANIC - *logofs << "DecompressPng24: PANIC! " - << "Failed png_create_info_struct operation" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, NULL, NULL); - - return -1; - } - - if (setjmp(png_jmpbuf(pngPtr))) - { - #ifdef PANIC - *logofs << "DecompressPng24: PANIC! " - << "Error during IO initialization" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - - return -1; - } - - png_set_read_fn(pngPtr, (void *)compressedData, PngReadData); - - if (setjmp(png_jmpbuf(pngPtr))) - { - #ifdef PANIC - *logofs << "DecompressPng24: PANIC! " - << "Error during read of PNG header" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - - return -1; - } - - png_read_info( pngPtr, infoPtr ) ; - - if (png_get_color_type(pngPtr, infoPtr) == PNG_COLOR_TYPE_PALETTE) - { - png_set_expand(pngPtr); - } - - // - // PixelPtr points to dstBuf which is - // already padded correctly for the final - // image to put - // - - pixelPtr = (CARD8 *) dstBuf; - - rowPointers = (png_byte *)tmpBuf; - - if (setjmp(png_jmpbuf(pngPtr))) - { - #ifdef PANIC - *logofs << "DecompressPng24: PANIC! " - << "Error during read of PNG rows" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - - return -1; - } - - for (dy = 0; dy < h; dy++) - { - png_read_row(pngPtr, rowPointers, NULL); - - for (dx = 0; dx < w; dx++) - { - // - // Follow the server byte order when arranging data. - // - - if (byteOrder == LSBFirst) - { - pixelPtr[0] = tmpBuf[dx * 3]; - pixelPtr[1] = tmpBuf[dx * 3 + 1]; - pixelPtr[2] = tmpBuf[dx * 3 + 2]; - } - else - { - pixelPtr[2] = tmpBuf[dx * 3]; - pixelPtr[1] = tmpBuf[dx * 3 + 1]; - pixelPtr[0] = tmpBuf[dx * 3 + 2]; - } - - pixelPtr += 3; - } - - // - // Go to the next line. - // - - pixelPtr = (CARD8 *) (((char *) pixelPtr) + (RoundUp4(w * 3) - w * 3)); - } - - png_destroy_read_struct(&pngPtr, &infoPtr,NULL); - - #ifdef DEBUG - *logofs << "DecompressPng24: Decompression finished." - << dy << " lines handled.\n" - << logofs_flush; - #endif - - return 1; -} - -int DecompressPng32(unsigned char *compressedData, int compressedLen, - unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) -{ - unsigned char *data; - - unsigned int dx, dy; - - png_structp pngPtr; - png_infop infoPtr; - png_bytep rowPointers; - - streamPos = 0; - - pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!pngPtr) - { - #ifdef PANIC - *logofs << "DecompressPng32: PANIC! " - << "Failed png_create_read_struct operation" - << ".\n" << logofs_flush; - #endif - - return -1; - } - - infoPtr = png_create_info_struct(pngPtr); - - if (!infoPtr) - { - #ifdef PANIC - *logofs << "DecompressPng32: PANIC! " - << "Failed png_create_info_struct operation." - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, NULL, NULL); - - return -1; - } - - if (setjmp(png_jmpbuf(pngPtr))) - { - #ifdef PANIC - *logofs << "DecompressPng32: PANIC! " - << "Error during IO initialization" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - - return -1; - } - - png_set_read_fn(pngPtr, (void *)compressedData, PngReadData); - - if (setjmp(png_jmpbuf(pngPtr))) - { - #ifdef PANIC - *logofs << "DecompressPng32: PANIC! " - << "Error during read of PNG header" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - - return -1; - } - - png_read_info(pngPtr, infoPtr) ; - - - if (png_get_color_type(pngPtr, infoPtr) == PNG_COLOR_TYPE_PALETTE) - { - png_set_expand(pngPtr); - } - - // - // data points to dstBuf which is - // already padded correctly for the final - // image to put - // - - data = dstBuf; - - rowPointers = (png_byte *) tmpBuf; - - if (setjmp(png_jmpbuf(pngPtr))) - { - #ifdef PANIC - *logofs << "DecompressPng32: PANIC! " - << "Error during read of PNG rows" - << ".\n" << logofs_flush; - #endif - - png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - - return -1; - } - - unsigned long pixel; - - int i; - - for (dy = 0; dy < h; dy++) - { - png_read_row(pngPtr, rowPointers, NULL); - - for (dx = 0; dx < w; dx++) - { - pixel = RGB24_TO_PIXEL(32, tmpBuf[dx * 3], tmpBuf[dx * 3 + 1], - tmpBuf[dx * 3 + 2]); - - // - // Follow the server byte order when arranging data. - // - - if (byteOrder == LSBFirst) - { - for (i = 0; i < 4; i++) - { - data[i] = (unsigned char)(pixel & 0xff); - pixel >>= 8; - } - } - else - { - for (i = 3; i >= 0; i--) - { - data[i] = (unsigned char) (pixel & 0xff); - pixel >>= 8; - } - } - - data += 4; - } - } - - png_destroy_read_struct(&pngPtr, &infoPtr,NULL); - - #ifdef DEBUG - *logofs << "DecompressPng32: Decompression finished." - << dy << " lines handled.\n" - << logofs_flush; - #endif - - return 1; -} - -static void PngReadData(png_structp png_ptr, png_bytep data, png_size_t length) -{ - memcpy((char *) data, (char *) png_get_io_ptr(png_ptr) + streamPos, length); - - streamPos += length; -} diff --git a/nxcomp/Pgn.h b/nxcomp/Pgn.h deleted file mode 100644 index e5ea36715..000000000 --- a/nxcomp/Pgn.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Pgn_H -#define Pgn_H - -// -// This file obviously supports PNG -// decompression. It was renamed to -// avoid name clashes on Windows. -// - -#include "Misc.h" -#include "Unpack.h" - -int UnpackPng(T_geometry *geometry, unsigned char method, unsigned char *srcData, - int srcSize, int dstBpp, int dstWidth, int dstHeight, - unsigned char *dstData, int dstSize); - -#endif /* Pgn_H */ diff --git a/nxcomp/Pipe.cpp b/nxcomp/Pipe.cpp deleted file mode 100644 index 88f10edb4..000000000 --- a/nxcomp/Pipe.cpp +++ /dev/null @@ -1,429 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include "Pipe.h" -#include "Misc.h" -#include "Fork.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -extern void RegisterChild(int child); - -static int Psplit(const char *command, char *parameters[], int limit); - -// -// These are slightly modified versions of popen(3) and pclose(3) -// that don't rely on a shell to be available on the system, so -// that they can also work on Windows. As an additional benefit, -// these functions give up all privileges before running the com- -// mand. Code is taken from the X distribution and, in turn, is -// based on libc from FreeBSD 2.2. -// - -static struct pid -{ - struct pid *next; - FILE *fp; - int self; - -} *pidlist; - -// -// A very unsofisticated attempt to parse the command line and -// split each parameter in distinct strings. This is not going -// to work when dealing with parameters containing spaces, even -// if they are enclosed in quotes. -// - -int Psplit(const char *command, char *parameters[], int limit) -{ - char *line; - char *value; - - int number; - - // - // Preapare the list of parameters. - // - - for (number = 0; number < limit; number++) - { - parameters[number] = NULL; - } - - // - // Copy the command to get rid of the - // const qualifier. - // - - line = new char[strlen(command) + 1]; - - if (line == NULL) - { - goto PsplitError; - } - - strcpy(line, command); - - number = 0; - - value = strtok(line, " "); - - while (value != NULL && number < limit) - { - #ifdef DEBUG - *logofs << "Psplit: Got parameter '" << value - << "'.\n" << logofs_flush; - #endif - - parameters[number] = new char[strlen(value) + 1]; - - if (parameters[number] == NULL) - { - goto PsplitError; - } - - strcpy(parameters[number], value); - - number++; - - // - // If this is the first parameter, then - // copy it in the second position and - // use it as the name of the command. - // - - if (number == 1) - { - parameters[number] = new char[strlen(value) + 1]; - - if (parameters[number] == NULL) - { - goto PsplitError; - } - - strcpy(parameters[number], value); - - number++; - } - - value = strtok(NULL, " "); - } - - // - // Needs at least to have the command itself and - // the first argument, being again the name of - // the command. - // - - if (number < 2) - { - goto PsplitError; - } - - return number; - -PsplitError: - - #ifdef PANIC - *logofs << "Psplit: PANIC! Can't split command line '" - << command << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't split command line '" - << command << "'.\n"; - - delete [] line; - - return -1; -} - -FILE *Popen(char * const parameters[], const char *type) -{ - FILE *iop; - - struct pid *cur; - int pdes[2], pid; - - if (parameters == NULL || type == NULL) - { - return NULL; - } - - if ((*type != 'r' && *type != 'w') || type[1]) - { - return NULL; - } - - if ((cur = (struct pid *) malloc(sizeof(struct pid))) == NULL) - { - return NULL; - } - - if (pipe(pdes) < 0) - { - free(cur); - - return NULL; - } - - // - // Block all signals until command is exited. - // We need to gather information about the - // child in Pclose(). - // - - DisableSignals(); - - switch (pid = Fork()) - { - case -1: - { - // - // Error. - // - - #ifdef PANIC - *logofs << "Popen: PANIC! Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Function fork failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - close(pdes[0]); - close(pdes[1]); - - free(cur); - - return NULL; - } - case 0: - { - // - // Child. - // - - struct passwd *pwent = getpwuid(getuid()); - if (pwent) initgroups(pwent->pw_name,getgid()); - if (setgid(getgid()) == -1) - { - _exit(127); - } - if (setuid(getuid()) == -1) - { - _exit(127); - } - - if (*type == 'r') - { - if (pdes[1] != 1) - { - // - // Set up stdout. - // - - dup2(pdes[1], 1); - close(pdes[1]); - } - - close(pdes[0]); - } - else - { - if (pdes[0] != 0) - { - // - // Set up stdin. - // - - dup2(pdes[0], 0); - close(pdes[0]); - } - - close(pdes[1]); - } - - execvp(parameters[0], parameters + 1); - - exit(127); - } - } - - // - // Parent. Save data about the child. - // - - RegisterChild(pid); - - if (*type == 'r') - { - iop = fdopen(pdes[0], type); - - close(pdes[1]); - } - else - { - iop = fdopen(pdes[1], type); - - close(pdes[0]); - } - - cur -> fp = iop; - cur -> self = pid; - cur -> next = pidlist; - - pidlist = cur; - - #ifdef TEST - *logofs << "Popen: Executing "; - - for (int i = 0; i < 256 && parameters[i] != NULL; i++) - { - *logofs << "[" << parameters[i] << "]"; - } - - *logofs << " with descriptor " << fileno(iop) - << ".\n" << logofs_flush; - #endif - - return iop; -} - -FILE *Popen(const char *command, const char *type) -{ - char *parameters[256]; - - if (Psplit(command, parameters, 256) > 0) - { - FILE *file = Popen(parameters, type); - - for (int i = 0; i < 256; i++) - { - delete [] parameters[i]; - } - - return file; - } - else - { - #ifdef PANIC - *logofs << "Popen: PANIC! Failed to parse command '" - << command << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to parse command '" - << command << "'.\n"; - - return NULL; - } -} - -int Pclose(FILE *iop) -{ - struct pid *cur, *last; - - int pstat; - int pid; - - #ifdef TEST - *logofs << "Pclose: Closing command with output " - << "on descriptor " << fileno(iop) << ".\n" - << logofs_flush; - #endif - - fclose((FILE *) iop); - - for (last = NULL, cur = pidlist; cur; last = cur, cur = cur -> next) - { - if (cur -> fp == iop) - { - break; - } - } - - if (cur == NULL) - { - #ifdef PANIC - *logofs << "Pclose: PANIC! Failed to find the process " - << "for descriptor " << fileno(iop) << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed to find the process " - << "for descriptor " << fileno(iop) << ".\n"; - - return -1; - } - - do - { - #ifdef TEST - *logofs << "Pclose: Going to wait for process " - << "with pid '" << cur -> self << "'.\n" - << logofs_flush; - #endif - - pid = waitpid(cur -> self, &pstat, 0); - } - while (pid == -1 && errno == EINTR); - - if (last == NULL) - { - pidlist = cur -> next; - } - else - { - last -> next = cur -> next; - } - - free(cur); - - // - // Child has finished and we called the - // waitpid(). We can enable signals again. - // - - EnableSignals(); - - return (pid == -1 ? -1 : pstat); -} diff --git a/nxcomp/Pipe.h b/nxcomp/Pipe.h deleted file mode 100644 index fd1061d30..000000000 --- a/nxcomp/Pipe.h +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// These are slightly modified versions of popen(3) and pclose(3) -// that don't rely on a shell to be available on the system, so -// that they can also work on Windows. -// - -extern FILE *Popen(char * const parameters[], const char *type); -extern FILE *Popen(const char *command, const char *type); - -extern int Pclose(FILE *file); diff --git a/nxcomp/PolyArc.cpp b/nxcomp/PolyArc.cpp deleted file mode 100644 index 8996c6f15..000000000 --- a/nxcomp/PolyArc.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PolyArc.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int PolyArcStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyArcMessage *polyArc = (PolyArcMessage *) message; - - // - // Here is the fingerprint. - // - - polyArc -> drawable = GetULONG(buffer + 4, bigEndian); - polyArc -> gcontext = GetULONG(buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PolyArcStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyArcMessage *polyArc = (PolyArcMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(polyArc -> drawable, buffer + 4, bigEndian); - PutULONG(polyArc -> gcontext, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PolyArcStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PolyArcMessage *polyArc = (PolyArcMessage *) message; - - *logofs << name() << ": Identity drawable " << polyArc -> drawable - << ", gcontext " << polyArc -> gcontext - << ", size " << polyArc -> size_ << ".\n" << logofs_flush; - #endif -} - -void PolyArcStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -} - -void PolyArcStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - PolyArcMessage *polyArc = (PolyArcMessage *) message; - PolyArcMessage *cachedPolyArc = (PolyArcMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyArc -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyArc -> drawable, clientCache -> drawableCache); - - cachedPolyArc -> drawable = polyArc -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyArc -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyArc -> gcontext, clientCache -> gcCache); - - cachedPolyArc -> gcontext = polyArc -> gcontext; -} - -void PolyArcStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - PolyArcMessage *polyArc = (PolyArcMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - polyArc -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyArc -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - polyArc -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyArc -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/PolyArc.h b/nxcomp/PolyArc.h deleted file mode 100644 index d744d6a10..000000000 --- a/nxcomp/PolyArc.h +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PolyArc_H -#define PolyArc_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define POLYARC_ENABLE_CACHE 1 -#define POLYARC_ENABLE_DATA 0 -#define POLYARC_ENABLE_SPLIT 0 -#define POLYARC_ENABLE_COMPRESS 0 - -#define POLYARC_DATA_LIMIT 1980 -#define POLYARC_DATA_OFFSET 12 - -#define POLYARC_CACHE_SLOTS 2000 -#define POLYARC_CACHE_THRESHOLD 2 -#define POLYARC_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class PolyArcMessage : public Message -{ - friend class PolyArcStore; - - public: - - PolyArcMessage() - { - } - - ~PolyArcMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int drawable; - unsigned int gcontext; -}; - -class PolyArcStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - PolyArcStore() : MessageStore() - { - enableCache = POLYARC_ENABLE_CACHE; - enableData = POLYARC_ENABLE_DATA; - enableSplit = POLYARC_ENABLE_SPLIT; - enableCompress = POLYARC_ENABLE_COMPRESS; - - dataLimit = POLYARC_DATA_LIMIT; - dataOffset = POLYARC_DATA_OFFSET; - - cacheSlots = POLYARC_CACHE_SLOTS; - cacheThreshold = POLYARC_CACHE_THRESHOLD; - cacheLowerThreshold = POLYARC_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~PolyArcStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "PolyArc"; - } - - virtual unsigned char opcode() const - { - return X_PolyArc; - } - - virtual unsigned int storage() const - { - return sizeof(PolyArcMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new PolyArcMessage(); - } - - virtual Message *create(const Message &message) const - { - return new PolyArcMessage((const PolyArcMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (PolyArcMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PolyArc_H */ diff --git a/nxcomp/PolyFillArc.cpp b/nxcomp/PolyFillArc.cpp deleted file mode 100644 index f995a8815..000000000 --- a/nxcomp/PolyFillArc.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PolyFillArc.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int PolyFillArcStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; - - // - // Here is the fingerprint. - // - - polyFillArc -> drawable = GetULONG(buffer + 4, bigEndian); - polyFillArc -> gcontext = GetULONG(buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PolyFillArcStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(polyFillArc -> drawable, buffer + 4, bigEndian); - PutULONG(polyFillArc -> gcontext, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PolyFillArcStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; - - *logofs << name() << ": Identity drawable " << polyFillArc -> drawable - << ", gcontext " << polyFillArc -> gcontext - << ", size " << polyFillArc -> size_ << ".\n" << logofs_flush; - #endif -} - -void PolyFillArcStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -} - -void PolyFillArcStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; - PolyFillArcMessage *cachedPolyFillArc = (PolyFillArcMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyFillArc -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyFillArc -> drawable, clientCache -> drawableCache); - - cachedPolyFillArc -> drawable = polyFillArc -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyFillArc -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyFillArc -> gcontext, clientCache -> gcCache); - - cachedPolyFillArc -> gcontext = polyFillArc -> gcontext; -} - -void PolyFillArcStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - polyFillArc -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyFillArc -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - polyFillArc -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyFillArc -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/PolyFillArc.h b/nxcomp/PolyFillArc.h deleted file mode 100644 index a4eff5b48..000000000 --- a/nxcomp/PolyFillArc.h +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PolyFillArc_H -#define PolyFillArc_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define POLYFILLARC_ENABLE_CACHE 1 -#define POLYFILLARC_ENABLE_DATA 0 -#define POLYFILLARC_ENABLE_SPLIT 0 -#define POLYFILLARC_ENABLE_COMPRESS 0 - -#define POLYFILLARC_DATA_LIMIT 6144 -#define POLYFILLARC_DATA_OFFSET 12 - -#define POLYFILLARC_CACHE_SLOTS 2000 -#define POLYFILLARC_CACHE_THRESHOLD 2 -#define POLYFILLARC_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class PolyFillArcMessage : public Message -{ - friend class PolyFillArcStore; - - public: - - PolyFillArcMessage() - { - } - - ~PolyFillArcMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int drawable; - unsigned int gcontext; -}; - -class PolyFillArcStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - PolyFillArcStore() : MessageStore() - { - enableCache = POLYFILLARC_ENABLE_CACHE; - enableData = POLYFILLARC_ENABLE_DATA; - enableSplit = POLYFILLARC_ENABLE_SPLIT; - enableCompress = POLYFILLARC_ENABLE_COMPRESS; - - dataLimit = POLYFILLARC_DATA_LIMIT; - dataOffset = POLYFILLARC_DATA_OFFSET; - - cacheSlots = POLYFILLARC_CACHE_SLOTS; - cacheThreshold = POLYFILLARC_CACHE_THRESHOLD; - cacheLowerThreshold = POLYFILLARC_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~PolyFillArcStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "PolyFillArc"; - } - - virtual unsigned char opcode() const - { - return X_PolyFillArc; - } - - virtual unsigned int storage() const - { - return sizeof(PolyFillArcMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new PolyFillArcMessage(); - } - - virtual Message *create(const Message &message) const - { - return new PolyFillArcMessage((const PolyFillArcMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (PolyFillArcMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PolyFillArc_H */ diff --git a/nxcomp/PolyFillRectangle.cpp b/nxcomp/PolyFillRectangle.cpp deleted file mode 100644 index d0f1452b2..000000000 --- a/nxcomp/PolyFillRectangle.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PolyFillRectangle.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int PolyFillRectangleStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; - - // - // Here is the fingerprint. - // - - polyFillRectangle -> drawable = GetULONG(buffer + 4, bigEndian); - polyFillRectangle -> gcontext = GetULONG(buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PolyFillRectangleStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(polyFillRectangle -> drawable, buffer + 4, bigEndian); - PutULONG(polyFillRectangle -> gcontext, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PolyFillRectangleStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; - - *logofs << name() << ": Identity drawable " << polyFillRectangle -> drawable - << ", gcontext " << polyFillRectangle -> gcontext - << ", size " << polyFillRectangle -> size_ << ".\n" << logofs_flush; - #endif -} - -void PolyFillRectangleStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -} - -void PolyFillRectangleStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; - PolyFillRectangleMessage *cachedPolyFillRectangle = (PolyFillRectangleMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding value " << polyFillRectangle -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyFillRectangle -> drawable, clientCache -> drawableCache); - - cachedPolyFillRectangle -> drawable = polyFillRectangle -> drawable; - - #ifdef DEBUG - *logofs << name() << ": Encoding value " << polyFillRectangle -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyFillRectangle -> gcontext, clientCache -> gcCache); - - cachedPolyFillRectangle -> gcontext = polyFillRectangle -> gcontext; -} - -void PolyFillRectangleStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - polyFillRectangle -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyFillRectangle -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - polyFillRectangle -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyFillRectangle -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} diff --git a/nxcomp/PolyFillRectangle.h b/nxcomp/PolyFillRectangle.h deleted file mode 100644 index 7ebb9270d..000000000 --- a/nxcomp/PolyFillRectangle.h +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PolyFillRectangle_H -#define PolyFillRectangle_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define POLYFILLRECTANGLE_ENABLE_CACHE 1 -#define POLYFILLRECTANGLE_ENABLE_DATA 0 -#define POLYFILLRECTANGLE_ENABLE_SPLIT 0 -#define POLYFILLRECTANGLE_ENABLE_COMPRESS 0 - -#define POLYFILLRECTANGLE_DATA_LIMIT 2048 -#define POLYFILLRECTANGLE_DATA_OFFSET 12 - -#define POLYFILLRECTANGLE_CACHE_SLOTS 4000 -#define POLYFILLRECTANGLE_CACHE_THRESHOLD 5 -#define POLYFILLRECTANGLE_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class PolyFillRectangleMessage : public Message -{ - friend class PolyFillRectangleStore; - - public: - - PolyFillRectangleMessage() - { - } - - ~PolyFillRectangleMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int drawable; - unsigned int gcontext; -}; - -class PolyFillRectangleStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - PolyFillRectangleStore() : MessageStore() - { - enableCache = POLYFILLRECTANGLE_ENABLE_CACHE; - enableData = POLYFILLRECTANGLE_ENABLE_DATA; - enableSplit = POLYFILLRECTANGLE_ENABLE_SPLIT; - enableCompress = POLYFILLRECTANGLE_ENABLE_COMPRESS; - - dataLimit = POLYFILLRECTANGLE_DATA_LIMIT; - dataOffset = POLYFILLRECTANGLE_DATA_OFFSET; - - cacheSlots = POLYFILLRECTANGLE_CACHE_SLOTS; - cacheThreshold = POLYFILLRECTANGLE_CACHE_THRESHOLD; - cacheLowerThreshold = POLYFILLRECTANGLE_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~PolyFillRectangleStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "PolyFillRectangle"; - } - - virtual unsigned char opcode() const - { - return X_PolyFillRectangle; - } - - virtual unsigned int storage() const - { - return sizeof(PolyFillRectangleMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new PolyFillRectangleMessage(); - } - - virtual Message *create(const Message &message) const - { - return new PolyFillRectangleMessage((const PolyFillRectangleMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (PolyFillRectangleMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PolyFillRectangle_H */ diff --git a/nxcomp/PolyLine.cpp b/nxcomp/PolyLine.cpp deleted file mode 100644 index 845985728..000000000 --- a/nxcomp/PolyLine.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PolyLine.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int PolyLineStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyLineMessage *polyLine = (PolyLineMessage *) message; - - // - // Here is the fingerprint. - // - - polyLine -> mode = *(buffer + 1); - - polyLine -> drawable = GetULONG(buffer + 4, bigEndian); - polyLine -> gcontext = GetULONG(buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PolyLineStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyLineMessage *polyLine = (PolyLineMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = polyLine -> mode; - - PutULONG(polyLine -> drawable, buffer + 4, bigEndian); - PutULONG(polyLine -> gcontext, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PolyLineStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PolyLineMessage *polyLine = (PolyLineMessage *) message; - - *logofs << name() << ": Identity drawable " << polyLine -> drawable - << ", gcontext " << polyLine -> gcontext - << ", size " << polyLine -> size_ << ".\n" << logofs_flush; - #endif -} - -void PolyLineStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // Since ProtoStep8 (#issue 108) - md5_append(md5_state_, buffer + 1, 1); -} - -void PolyLineStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - PolyLineMessage *polyLine = (PolyLineMessage *) message; - PolyLineMessage *cachedPolyLine = (PolyLineMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyLine -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyLine -> drawable, clientCache -> drawableCache); - - cachedPolyLine -> drawable = polyLine -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyLine -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyLine -> gcontext, clientCache -> gcCache); - - cachedPolyLine -> gcontext = polyLine -> gcontext; -} - -void PolyLineStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - PolyLineMessage *polyLine = (PolyLineMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - polyLine -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyLine -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - polyLine -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyLine -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/PolyLine.h b/nxcomp/PolyLine.h deleted file mode 100644 index 66fa5df1a..000000000 --- a/nxcomp/PolyLine.h +++ /dev/null @@ -1,186 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PolyLine_H -#define PolyLine_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define POLYLINE_ENABLE_CACHE 1 -#define POLYLINE_ENABLE_DATA 0 -#define POLYLINE_ENABLE_SPLIT 0 -#define POLYLINE_ENABLE_COMPRESS 0 - -#define POLYLINE_DATA_LIMIT 144 -#define POLYLINE_DATA_OFFSET 12 - -#define POLYLINE_CACHE_SLOTS 3000 -#define POLYLINE_CACHE_THRESHOLD 3 -#define POLYLINE_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class PolyLineMessage : public Message -{ - friend class PolyLineStore; - - public: - - PolyLineMessage() - { - } - - ~PolyLineMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char mode; - unsigned int drawable; - unsigned int gcontext; -}; - -class PolyLineStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - PolyLineStore() : MessageStore() - { - enableCache = POLYLINE_ENABLE_CACHE; - enableData = POLYLINE_ENABLE_DATA; - enableSplit = POLYLINE_ENABLE_SPLIT; - enableCompress = POLYLINE_ENABLE_COMPRESS; - - dataLimit = POLYLINE_DATA_LIMIT; - dataOffset = POLYLINE_DATA_OFFSET; - - cacheSlots = POLYLINE_CACHE_SLOTS; - cacheThreshold = POLYLINE_CACHE_THRESHOLD; - cacheLowerThreshold = POLYLINE_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~PolyLineStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "PolyLine"; - } - - virtual unsigned char opcode() const - { - return X_PolyLine; - } - - virtual unsigned int storage() const - { - return sizeof(PolyLineMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new PolyLineMessage(); - } - - virtual Message *create(const Message &message) const - { - return new PolyLineMessage((const PolyLineMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (PolyLineMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PolyLine_H */ diff --git a/nxcomp/PolyPoint.cpp b/nxcomp/PolyPoint.cpp deleted file mode 100644 index dfd77f40b..000000000 --- a/nxcomp/PolyPoint.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PolyPoint.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int PolyPointStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyPointMessage *polyPoint = (PolyPointMessage *) message; - - // - // Here is the fingerprint. - // - - polyPoint -> mode = *(buffer + 1); - - polyPoint -> drawable = GetULONG(buffer + 4, bigEndian); - polyPoint -> gcontext = GetULONG(buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PolyPointStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyPointMessage *polyPoint = (PolyPointMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = polyPoint -> mode; - - PutULONG(polyPoint -> drawable, buffer + 4, bigEndian); - PutULONG(polyPoint -> gcontext, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PolyPointStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PolyPointMessage *polyPoint = (PolyPointMessage *) message; - - *logofs << name() << ": Identity drawable " << polyPoint -> drawable - << ", gcontext " << polyPoint -> gcontext - << ", size " << polyPoint -> size_ << ".\n" << logofs_flush; - #endif -} - -void PolyPointStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // Since ProtoStep8 (#issue 108) - md5_append(md5_state_, buffer + 1, 1); -} - -void PolyPointStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - PolyPointMessage *polyPoint = (PolyPointMessage *) message; - PolyPointMessage *cachedPolyPoint = (PolyPointMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyPoint -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyPoint -> drawable, clientCache -> drawableCache); - - cachedPolyPoint -> drawable = polyPoint -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyPoint -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyPoint -> gcontext, clientCache -> gcCache); - - cachedPolyPoint -> gcontext = polyPoint -> gcontext; -} - -void PolyPointStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - PolyPointMessage *polyPoint = (PolyPointMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - polyPoint -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyPoint -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - polyPoint -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyPoint -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/PolyPoint.h b/nxcomp/PolyPoint.h deleted file mode 100644 index b8ea183bf..000000000 --- a/nxcomp/PolyPoint.h +++ /dev/null @@ -1,186 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PolyPoint_H -#define PolyPoint_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define POLYPOINT_ENABLE_CACHE 1 -#define POLYPOINT_ENABLE_DATA 0 -#define POLYPOINT_ENABLE_SPLIT 0 -#define POLYPOINT_ENABLE_COMPRESS 0 - -#define POLYPOINT_DATA_LIMIT 3200 -#define POLYPOINT_DATA_OFFSET 12 - -#define POLYPOINT_CACHE_SLOTS 3000 -#define POLYPOINT_CACHE_THRESHOLD 3 -#define POLYPOINT_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class PolyPointMessage : public Message -{ - friend class PolyPointStore; - - public: - - PolyPointMessage() - { - } - - ~PolyPointMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char mode; - unsigned int drawable; - unsigned int gcontext; -}; - -class PolyPointStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - PolyPointStore() : MessageStore() - { - enableCache = POLYPOINT_ENABLE_CACHE; - enableData = POLYPOINT_ENABLE_DATA; - enableSplit = POLYPOINT_ENABLE_SPLIT; - enableCompress = POLYPOINT_ENABLE_COMPRESS; - - dataLimit = POLYPOINT_DATA_LIMIT; - dataOffset = POLYPOINT_DATA_OFFSET; - - cacheSlots = POLYPOINT_CACHE_SLOTS; - cacheThreshold = POLYPOINT_CACHE_THRESHOLD; - cacheLowerThreshold = POLYPOINT_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~PolyPointStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "PolyPoint"; - } - - virtual unsigned char opcode() const - { - return X_PolyPoint; - } - - virtual unsigned int storage() const - { - return sizeof(PolyPointMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new PolyPointMessage(); - } - - virtual Message *create(const Message &message) const - { - return new PolyPointMessage((const PolyPointMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (PolyPointMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PolyPoint_H */ diff --git a/nxcomp/PolySegment.cpp b/nxcomp/PolySegment.cpp deleted file mode 100644 index 34c2461f1..000000000 --- a/nxcomp/PolySegment.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PolySegment.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int PolySegmentStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolySegmentMessage *polySegment = (PolySegmentMessage *) message; - - // - // Here is the fingerprint. - // - - polySegment -> drawable = GetULONG(buffer + 4, bigEndian); - polySegment -> gcontext = GetULONG(buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PolySegmentStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolySegmentMessage *polySegment = (PolySegmentMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(polySegment -> drawable, buffer + 4, bigEndian); - PutULONG(polySegment -> gcontext, buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PolySegmentStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PolySegmentMessage *polySegment = (PolySegmentMessage *) message; - - *logofs << name() << ": Identity drawable " << polySegment -> drawable - << ", gcontext " << polySegment -> gcontext - << ", size " << polySegment -> size_ << ".\n" << logofs_flush; - #endif -} - -void PolySegmentStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -} - -void PolySegmentStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - PolySegmentMessage *polySegment = (PolySegmentMessage *) message; - PolySegmentMessage *cachedPolySegment = (PolySegmentMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polySegment -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polySegment -> drawable, clientCache -> drawableCache); - - cachedPolySegment -> drawable = polySegment -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polySegment -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polySegment -> gcontext, clientCache -> gcCache); - - cachedPolySegment -> gcontext = polySegment -> gcontext; -} - -void PolySegmentStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - PolySegmentMessage *polySegment = (PolySegmentMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - polySegment -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polySegment -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - polySegment -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polySegment -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/PolySegment.h b/nxcomp/PolySegment.h deleted file mode 100644 index 53fd42c60..000000000 --- a/nxcomp/PolySegment.h +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PolySegment_H -#define PolySegment_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define POLYSEGMENT_ENABLE_CACHE 1 -#define POLYSEGMENT_ENABLE_DATA 0 -#define POLYSEGMENT_ENABLE_SPLIT 0 -#define POLYSEGMENT_ENABLE_COMPRESS 0 - -#define POLYSEGMENT_DATA_LIMIT 8192 -#define POLYSEGMENT_DATA_OFFSET 12 - -#define POLYSEGMENT_CACHE_SLOTS 3000 -#define POLYSEGMENT_CACHE_THRESHOLD 5 -#define POLYSEGMENT_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class PolySegmentMessage : public Message -{ - friend class PolySegmentStore; - - public: - - PolySegmentMessage() - { - } - - ~PolySegmentMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int drawable; - unsigned int gcontext; -}; - -class PolySegmentStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - PolySegmentStore() : MessageStore() - { - enableCache = POLYSEGMENT_ENABLE_CACHE; - enableData = POLYSEGMENT_ENABLE_DATA; - enableSplit = POLYSEGMENT_ENABLE_SPLIT; - enableCompress = POLYSEGMENT_ENABLE_COMPRESS; - - dataLimit = POLYSEGMENT_DATA_LIMIT; - dataOffset = POLYSEGMENT_DATA_OFFSET; - - cacheSlots = POLYSEGMENT_CACHE_SLOTS; - cacheThreshold = POLYSEGMENT_CACHE_THRESHOLD; - cacheLowerThreshold = POLYSEGMENT_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~PolySegmentStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "PolySegment"; - } - - virtual unsigned char opcode() const - { - return X_PolySegment; - } - - virtual unsigned int storage() const - { - return sizeof(PolySegmentMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new PolySegmentMessage(); - } - - virtual Message *create(const Message &message) const - { - return new PolySegmentMessage((const PolySegmentMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (PolySegmentMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PolySegment_H */ diff --git a/nxcomp/PolyText16.cpp b/nxcomp/PolyText16.cpp deleted file mode 100644 index 80c77a70f..000000000 --- a/nxcomp/PolyText16.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PolyText16.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int PolyText16Store::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyText16Message *polyText16 = (PolyText16Message *) message; - - // - // Here is the fingerprint. - // - - polyText16 -> drawable = GetULONG(buffer + 4, bigEndian); - polyText16 -> gcontext = GetULONG(buffer + 8, bigEndian); - - polyText16 -> x = GetUINT(buffer + 12, bigEndian); - polyText16 -> y = GetUINT(buffer + 14, bigEndian); - - // - // Clean up padding bytes. - // - - #ifdef DUMP - - DumpData(buffer, size); - - *logofs << "\n" << logofs_flush; - - #endif - - if ((int) size > dataOffset) - { - int current; - int length; - int delta; - int item; - - unsigned int nitem; - - unsigned char *pad = NULL; - unsigned char *end = NULL; - - delta = 1; - nitem = 0; - - #ifdef DUMP - *logofs << name() << " Size " << size << ".\n" << logofs_flush; - #endif - - // - // Data is a list of TextItem where element - // can be a string or a font shift. - // - - current = POLYTEXT16_DATA_OFFSET; - length = POLYTEXT16_DATA_OFFSET; - - do - { - #ifdef DUMP - *logofs << name() << " Current " << current << ".\n" << logofs_flush; - #endif - - item = GetUINT(buffer + length , bigEndian); - - if (item < 255) - { - // - // Text element. Number represents - // the 'Length of CHAR2B string' - // field. - // - - length += ((item * 2) + delta + 1); - - nitem++; - } - else if (item == 255) - { - // - // Element is a font shift. - // - - length += 5; - - nitem++; - } - - #ifdef DUMP - *logofs << name() << " Item " << item << ".\n" << logofs_flush; - #endif - - current += length; - } - while(current < (int) size && item != 0); - - #ifdef DUMP - *logofs << name() << " Final length " << length << ".\n" << logofs_flush; - #endif - - end = ((unsigned char *) buffer) + size; - - pad = ((unsigned char *) buffer) + length; - - for (; pad < end && nitem >= 1; pad++) - { - #ifdef DUMP - *logofs << name() << " Padding " << " .\n" << logofs_flush; - #endif - - *pad = 0; - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PolyText16Store::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyText16Message *polyText16 = (PolyText16Message *) message; - - // - // Fill all the message's fields. - // - - PutULONG(polyText16 -> drawable, buffer + 4, bigEndian); - PutULONG(polyText16 -> gcontext, buffer + 8, bigEndian); - - PutUINT(polyText16 -> x, buffer + 12, bigEndian); - PutUINT(polyText16 -> y, buffer + 14, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PolyText16Store::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PolyText16Message *polyText16 = (PolyText16Message *) message; - - *logofs << name() << ": Identity drawable " << polyText16 -> drawable - << ", gcontext " << polyText16 -> gcontext << ", x " << polyText16 -> x - << ", y " << polyText16 -> y << ", size " << polyText16 -> size_ - << ".\n"; - - #endif -} - -void PolyText16Store::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -} - -void PolyText16Store::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - PolyText16Message *polyText16 = (PolyText16Message *) message; - PolyText16Message *cachedPolyText16 = (PolyText16Message *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyText16 -> drawable - << " as " << "drawable" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyText16 -> drawable, clientCache -> drawableCache); - - cachedPolyText16 -> drawable = polyText16 -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyText16 -> gcontext - << " as " << "gcontext" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyText16 -> gcontext, clientCache -> gcCache); - - cachedPolyText16 -> gcontext = polyText16 -> gcontext; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyText16 -> x - << " as " << "x" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_x = polyText16 -> x - cachedPolyText16 -> x; - - encodeBuffer.encodeCachedValue(diff_x, 16, - clientCache -> polyTextCacheX); - - cachedPolyText16 -> x = polyText16 -> x; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyText16 -> y - << " as " << "y" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_y = polyText16 -> y - cachedPolyText16 -> y; - - encodeBuffer.encodeCachedValue(diff_y, 16, - clientCache -> polyTextCacheY); - - cachedPolyText16 -> y = polyText16 -> y; -} - -void PolyText16Store::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - PolyText16Message *polyText16 = (PolyText16Message *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - polyText16 -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyText16 -> drawable - << " as " << "drawable" << " field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - polyText16 -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyText16 -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> polyTextCacheX); - - polyText16 -> x += value; - polyText16 -> x &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyText16 -> x - << " as x field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> polyTextCacheY); - - polyText16 -> y += value; - polyText16 -> y &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyText16 -> y - << " as y field.\n" << logofs_flush; - #endif -} - - diff --git a/nxcomp/PolyText16.h b/nxcomp/PolyText16.h deleted file mode 100644 index 805e1fa04..000000000 --- a/nxcomp/PolyText16.h +++ /dev/null @@ -1,188 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PolyText16_H -#define PolyText16_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define POLYTEXT16_ENABLE_CACHE 1 -#define POLYTEXT16_ENABLE_DATA 0 -#define POLYTEXT16_ENABLE_SPLIT 0 -#define POLYTEXT16_ENABLE_COMPRESS 0 - -#define POLYTEXT16_DATA_LIMIT 420 -#define POLYTEXT16_DATA_OFFSET 16 - -#define POLYTEXT16_CACHE_SLOTS 3000 -#define POLYTEXT16_CACHE_THRESHOLD 4 -#define POLYTEXT16_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class PolyText16Message : public Message -{ - friend class PolyText16Store; - - public: - - PolyText16Message() - { - } - - ~PolyText16Message() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int drawable; - unsigned int gcontext; - - unsigned short x; - unsigned short y; -}; - -class PolyText16Store : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - PolyText16Store() : MessageStore() - { - enableCache = POLYTEXT16_ENABLE_CACHE; - enableData = POLYTEXT16_ENABLE_DATA; - enableSplit = POLYTEXT16_ENABLE_SPLIT; - enableCompress = POLYTEXT16_ENABLE_COMPRESS; - - dataLimit = POLYTEXT16_DATA_LIMIT; - dataOffset = POLYTEXT16_DATA_OFFSET; - - cacheSlots = POLYTEXT16_CACHE_SLOTS; - cacheThreshold = POLYTEXT16_CACHE_THRESHOLD; - cacheLowerThreshold = POLYTEXT16_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~PolyText16Store() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "PolyText16"; - } - - virtual unsigned char opcode() const - { - return X_PolyText16; - } - - virtual unsigned int storage() const - { - return sizeof(PolyText16Message); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new PolyText16Message(); - } - - virtual Message *create(const Message &message) const - { - return new PolyText16Message((const PolyText16Message &) message); - } - - virtual void destroy(Message *message) const - { - delete (PolyText16Message *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PolyText16_H */ diff --git a/nxcomp/PolyText8.cpp b/nxcomp/PolyText8.cpp deleted file mode 100644 index 50c21f79e..000000000 --- a/nxcomp/PolyText8.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PolyText8.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int PolyText8Store::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyText8Message *polyText8 = (PolyText8Message *) message; - - // - // Here is the fingerprint. - // - - polyText8 -> drawable = GetULONG(buffer + 4, bigEndian); - polyText8 -> gcontext = GetULONG(buffer + 8, bigEndian); - - polyText8 -> x = GetUINT(buffer + 12, bigEndian); - polyText8 -> y = GetUINT(buffer + 14, bigEndian); - - // - // Clean up padding bytes. - // - - #ifdef DUMP - - DumpData(buffer, size); - - *logofs << "\n\n" << logofs_flush; - - #endif - - if ((int) size > dataOffset) - { - int length; - int current; - int delta; - int item; - - unsigned int nitem; - - unsigned char *pad = NULL; - unsigned char *end = NULL; - - delta = 1; - nitem = 0; - - #ifdef DUMP - *logofs << name() << " Size " << size << ".\n" << logofs_flush; - #endif - - // - // Data is a list of TextItem where element - // can be a string or a font shift. - // - - current = POLYTEXT8_DATA_OFFSET; - length = POLYTEXT8_DATA_OFFSET; - - do - { - #ifdef DUMP - *logofs << name() << " Current " << current << ".\n" << logofs_flush; - #endif - - item = GetUINT(buffer + length , bigEndian); - - if (item < 255) - { - // - // Text element. Number represents - // the 'Length of string' field. - // - - length += (item + delta + 1); - - nitem++; - } - else if (item == 255) - { - // - // Element is a font shift. - // - - length += 5; - - nitem++; - } - - #ifdef DUMP - *logofs << name() << " Item " << item << ".\n" << logofs_flush; - #endif - - current += length; - } - while(current < (int) size && item != 0); - - - #ifdef DUMP - *logofs << name() << " Final length " << length << ".\n" << logofs_flush; - #endif - - end = ((unsigned char *) buffer) + size; - - pad = ((unsigned char *) buffer) + length; - - for (; pad < end && nitem >= 1; pad++) - { - #ifdef DUMP - *logofs << name() << " Padding " << " .\n" << logofs_flush; - #endif - - *pad = 0; - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PolyText8Store::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PolyText8Message *polyText8 = (PolyText8Message *) message; - - // - // Fill all the message's fields. - // - - PutULONG(polyText8 -> drawable, buffer + 4, bigEndian); - PutULONG(polyText8 -> gcontext, buffer + 8, bigEndian); - - PutUINT(polyText8 -> x, buffer + 12, bigEndian); - PutUINT(polyText8 -> y, buffer + 14, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PolyText8Store::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PolyText8Message *polyText8 = (PolyText8Message *) message; - - *logofs << name() << ": Identity drawable " << polyText8 -> drawable - << ", gcontext " << polyText8 -> gcontext << ", x " << polyText8 -> x - << ", y " << polyText8 -> y << ", size " << polyText8 -> size_ - << ".\n"; - - #endif -} - -void PolyText8Store::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -} - -void PolyText8Store::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - PolyText8Message *polyText8 = (PolyText8Message *) message; - PolyText8Message *cachedPolyText8 = (PolyText8Message *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyText8 -> drawable - << " as " << "drawable" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyText8 -> drawable, clientCache -> drawableCache); - - cachedPolyText8 -> drawable = polyText8 -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyText8 -> gcontext - << " as " << "gcontext" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(polyText8 -> gcontext, clientCache -> gcCache); - - cachedPolyText8 -> gcontext = polyText8 -> gcontext; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyText8 -> x - << " as " << "x" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_x = polyText8 -> x - cachedPolyText8 -> x; - - encodeBuffer.encodeCachedValue(diff_x, 16, - clientCache -> polyTextCacheX); - - cachedPolyText8 -> x = polyText8 -> x; - - #ifdef TEST - *logofs << name() << ": Encoding value " << polyText8 -> y - << " as " << "y" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_y = polyText8 -> y - cachedPolyText8 -> y; - - encodeBuffer.encodeCachedValue(diff_y, 16, - clientCache -> polyTextCacheY); - - cachedPolyText8 -> y = polyText8 -> y; -} - -void PolyText8Store::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - PolyText8Message *polyText8 = (PolyText8Message *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - polyText8 -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyText8 -> drawable - << " as " << "drawable" << " field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - polyText8 -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyText8 -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> polyTextCacheX); - - polyText8 -> x += value; - polyText8 -> x &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyText8 -> x - << " as x field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> polyTextCacheY); - - polyText8 -> y += value; - polyText8 -> y &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << polyText8 -> y - << " as y field.\n" << logofs_flush; - #endif -} diff --git a/nxcomp/PolyText8.h b/nxcomp/PolyText8.h deleted file mode 100644 index 3d5ff533a..000000000 --- a/nxcomp/PolyText8.h +++ /dev/null @@ -1,188 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PolyText8_H -#define PolyText8_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define POLYTEXT8_ENABLE_CACHE 1 -#define POLYTEXT8_ENABLE_DATA 0 -#define POLYTEXT8_ENABLE_SPLIT 0 -#define POLYTEXT8_ENABLE_COMPRESS 0 - -#define POLYTEXT8_DATA_LIMIT 380 -#define POLYTEXT8_DATA_OFFSET 16 - -#define POLYTEXT8_CACHE_SLOTS 3000 -#define POLYTEXT8_CACHE_THRESHOLD 5 -#define POLYTEXT8_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class PolyText8Message : public Message -{ - friend class PolyText8Store; - - public: - - PolyText8Message() - { - } - - ~PolyText8Message() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int drawable; - unsigned int gcontext; - - unsigned short x; - unsigned short y; -}; - -class PolyText8Store : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - PolyText8Store() : MessageStore() - { - enableCache = POLYTEXT8_ENABLE_CACHE; - enableData = POLYTEXT8_ENABLE_DATA; - enableSplit = POLYTEXT8_ENABLE_SPLIT; - enableCompress = POLYTEXT8_ENABLE_COMPRESS; - - dataLimit = POLYTEXT8_DATA_LIMIT; - dataOffset = POLYTEXT8_DATA_OFFSET; - - cacheSlots = POLYTEXT8_CACHE_SLOTS; - cacheThreshold = POLYTEXT8_CACHE_THRESHOLD; - cacheLowerThreshold = POLYTEXT8_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~PolyText8Store() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "PolyText8"; - } - - virtual unsigned char opcode() const - { - return X_PolyText8; - } - - virtual unsigned int storage() const - { - return sizeof(PolyText8Message); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new PolyText8Message(); - } - - virtual Message *create(const Message &message) const - { - return new PolyText8Message((const PolyText8Message &) message); - } - - virtual void destroy(Message *message) const - { - delete (PolyText8Message *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PolyText8_H */ diff --git a/nxcomp/Proxy.cpp b/nxcomp/Proxy.cpp deleted file mode 100644 index 3a7a42362..000000000 --- a/nxcomp/Proxy.cpp +++ /dev/null @@ -1,6525 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef ANDROID -#include -#include -#include -#endif - -#include "Misc.h" - -#if defined(__CYGWIN32__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun) -#include -#endif - -#ifndef ANDROID -#include -#include -#include -#endif - -#include "NXalert.h" -#include "NXvars.h" - -#include "Proxy.h" - -#include "Socket.h" -#include "Channel.h" -#include "Statistics.h" - -#include "ClientChannel.h" -#include "ServerChannel.h" -#include "GenericChannel.h" -#include "ChannelEndPoint.h" - -// -// We need to adjust some values related -// to these messages at the time the mes- -// sage stores are reconfigured. -// - -#include "PutImage.h" -#include "ChangeGC.h" -#include "PolyFillRectangle.h" -#include "PutPackedImage.h" - -// -// This is from the main loop. -// - -extern void CleanupListeners(); - -extern int HandleChild(int); - -// -// Default size of string buffers. -// - -#define DEFAULT_STRING_LENGTH 512 - -// -// Set the verbosity level. You also need -// to define DUMP in Misc.cpp if DUMP is -// defined here. -// - -#define WARNING -#define PANIC -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Log the important tracepoints related -// to writing packets to the peer proxy. -// - -#undef FLUSH - -// -// Log the operations related to splits. -// - -#undef SPLIT - -// -// Log the operations related to sending -// and receiving the control tokens. -// - -#undef TOKEN - -// -// Log the operations related to setting -// the token limits. -// - -#undef LIMIT - -// -// Log a warning if no data is written by -// the proxy within a timeout. -// - -#undef TIME - -// -// Log the operation related to generating -// the ping message at idle time. -// - -#undef PING - -Proxy::Proxy(int fd) - - : transport_(new ProxyTransport(fd)), fd_(fd), readBuffer_(transport_) -{ - for (int channelId = 0; - channelId < CONNECTIONS_LIMIT; - channelId++) - { - channels_[channelId] = NULL; - transports_[channelId] = NULL; - congestions_[channelId] = 0; - - fdMap_[channelId] = nothing; - channelMap_[channelId] = nothing; - slavePidMap_[channelId] = nothing; - } - - inputChannel_ = nothing; - outputChannel_ = nothing; - - controlLength_ = 0; - - operation_ = operation_in_negotiation; - - draining_ = 0; - priority_ = 0; - finish_ = 0; - shutdown_ = 0; - congestion_ = 0; - - timer_ = 0; - alert_ = 0; - - agent_ = nothing; - - // - // Set null timeouts. This will require - // a new link configuration. - // - - timeouts_.split = 0; - timeouts_.motion = 0; - - timeouts_.readTs = getTimestamp(); - timeouts_.writeTs = getTimestamp(); - - timeouts_.loopTs = getTimestamp(); - timeouts_.pingTs = getTimestamp(); - timeouts_.alertTs = nullTimestamp(); - timeouts_.loadTs = nullTimestamp(); - - timeouts_.splitTs = nullTimestamp(); - timeouts_.motionTs = nullTimestamp(); - - // - // Initialize the token counters. This - // will require a new link configuration. - // - - for (int i = token_control; i <= token_data; i++) - { - tokens_[i].size = 0; - tokens_[i].limit = 0; - - tokens_[i].bytes = 0; - tokens_[i].remaining = 0; - } - - tokens_[token_control].request = code_control_token_request; - tokens_[token_control].reply = code_control_token_reply; - tokens_[token_control].type = token_control; - - tokens_[token_split].request = code_split_token_request; - tokens_[token_split].reply = code_split_token_reply; - tokens_[token_split].type = token_split; - - tokens_[token_data].request = code_data_token_request; - tokens_[token_data].reply = code_data_token_reply; - tokens_[token_data].type = token_data; - - currentStatistics_ = NULL; - - // - // Create compressor and decompressor - // for image and data payload. - // - - compressor_ = new StaticCompressor(control -> LocalDataCompressionLevel, - control -> LocalDataCompressionThreshold); - - // - // Create object storing NX specific - // opcodes. - // - - opcodeStore_ = new OpcodeStore(); - - // - // Create the message stores. - // - - clientStore_ = new ClientStore(compressor_); - serverStore_ = new ServerStore(compressor_); - - clientCache_ = new ClientCache(); - serverCache_ = new ServerCache(); - - if (clientCache_ == NULL || serverCache_ == NULL) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Failed to create the channel cache.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed to create the channel cache.\n"; - - HandleCleanup(); - } - - // - // Prepare for image decompression. - // - - UnpackInit(); - - #ifdef DEBUG - *logofs << "Proxy: Created new object at " << this - << ".\n" << logofs_flush; - #endif -} - -Proxy::~Proxy() -{ - for (int channelId = 0; - channelId < CONNECTIONS_LIMIT; - channelId++) - { - if (channels_[channelId] != NULL) - { - deallocateTransport(channelId); - - delete channels_[channelId]; - channels_[channelId] = NULL; - } - } - - // - // Kill all active slave channel children, and - // give them 5 seconds to exit nicely. - - #ifdef DEBUG - *logofs << "Proxy: Killing active slaves" << endl; - #endif - - int slave_count = 999; - int loop_count = 0; - - while(slave_count > 0 && loop_count < 50) - { - slave_count = 0; - - for (int channelId = 0; channelId 1) { - slave_count++; - - #ifdef DEBUG - *logofs << "Proxy: Active slave with pid " << pid << logofs_flush; - #endif - - if ( loop_count == 0 ) - { - #ifdef DEBUG - *logofs << "Proxy: Sending SIGTERM to " << pid << logofs_flush; - #endif - kill(pid, SIGTERM); - } - else if ( loop_count == 25 ) - { - #ifdef DEBUG - *logofs << "Proxy: Sending SIGKILL to " << pid << logofs_flush; - #endif - kill(pid, SIGKILL); - } - - if (HandleChild(pid)) - { - #ifdef DEBUG - *logofs << "Proxy: Slave " << pid << " terminated" << logofs_flush; - #endif - slavePidMap_[channelId] = nothing; - } - } - } - - if ( slave_count > 0 ) - { - cerr << "Proxy: Error: Failed to kill all slave channel processes. " << slave_count << " processes still remaining." << endl; - } - - usleep(200000); - loop_count++; - } - - delete transport_; - delete compressor_; - - // - // Delete storage shared among channels. - // - - delete opcodeStore_; - - delete clientStore_; - delete serverStore_; - - delete clientCache_; - delete serverCache_; - - // - // Get rid of the image decompression - // resources. - // - - UnpackDestroy(); - - #ifdef DEBUG - *logofs << "Proxy: Deleted proxy object at " << this - << ".\n" << logofs_flush; - #endif -} - -int Proxy::setOperational() -{ - #ifdef TEST - *logofs << "Proxy: Entering operational mode.\n" - << logofs_flush; - #endif - - operation_ = operation_in_messages; - - return 1; -} - -int Proxy::setReadDescriptors(fd_set *fdSet, int &fdMax, T_timestamp &tsMax) -{ - // - // Set the initial timeout to the time of - // the next ping. If the congestion count - // is greater than zero, anyway, use a - // shorter timeout to force a congestion - // update. - // - - if (agent_ != nothing && congestions_[agent_] == 0 && - statistics -> getCongestionInFrame() >= 1 && - tokens_[token_control].remaining >= - (tokens_[token_control].limit - 1)) - { - setMinTimestamp(tsMax, control -> IdleTimeout); - - #ifdef TEST - *logofs << "Proxy: Initial timeout is " << tsMax.tv_sec - << " S and " << (double) tsMax.tv_usec / - 1000 << " Ms with congestion " - << statistics -> getCongestionInFrame() - << ".\n" << logofs_flush; - #endif - } - else - { - setMinTimestamp(tsMax, control -> PingTimeout); - - #ifdef TEST - *logofs << "Proxy: Initial timeout is " << tsMax.tv_sec - << " S and " << (double) tsMax.tv_usec / - 1000 << " Ms.\n" << logofs_flush; - #endif - } - - int fd = -1; - - if (isTimeToRead() == 1) - { - // - // If we don't have split tokens available - // don't set the timeout. - // - - if (tokens_[token_split].remaining > 0 && - isTimestamp(timeouts_.splitTs) == 1) - { - int diffTs = getTimeToNextSplit(); - - #if defined(TEST) || defined(INFO) || \ - defined(FLUSH) || defined(SPLIT) - - if (diffTimestamp(timeouts_.splitTs, - getTimestamp()) > timeouts_.split) - { - *logofs << "Proxy: FLUSH! SPLIT! WARNING! Running with " - << diffTimestamp(timeouts_.splitTs, getTimestamp()) - << " Ms elapsed since the last split.\n" - << logofs_flush; - } - - *logofs << "Proxy: FLUSH! SPLIT! Requesting timeout of " - << diffTs << " Ms as there are splits to send.\n" - << logofs_flush; - - #endif - - setMinTimestamp(tsMax, diffTs); - } - #if defined(TEST) || defined(INFO) - else if (isTimestamp(timeouts_.splitTs) == 1) - { - *logofs << "Proxy: WARNING! Not requesting a split " - << "timeout with " << tokens_[token_split].remaining - << " split tokens remaining.\n" << logofs_flush; - } - #endif - - // - // Loop through the valid channels and set - // the descriptors selected for read and - // the timeout. - // - - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] == NULL) - { - continue; - } - - fd = getFd(channelId); - - if (channels_[channelId] -> getFinish() == 0 && - (channels_[channelId] -> getType() == channel_x11 || - tokens_[token_data].remaining > 0) && - congestions_[channelId] == 0) - { - FD_SET(fd, fdSet); - - if (fd >= fdMax) - { - fdMax = fd + 1; - } - - #ifdef TEST - *logofs << "Proxy: Descriptor FD#" << fd - << " selected for read with buffer length " - << transports_[channelId] -> length() - << ".\n" << logofs_flush; - #endif - - // - // Wakeup the proxy if there are motion - // events to flush. - // - - if (isTimestamp(timeouts_.motionTs) == 1) - { - int diffTs = getTimeToNextMotion(); - - #if defined(TEST) || defined(INFO) - - if (diffTimestamp(timeouts_.motionTs, - getTimestamp()) > timeouts_.motion) - { - *logofs << "Proxy: FLUSH! WARNING! Running with " - << diffTimestamp(timeouts_.motionTs, getTimestamp()) - << " Ms elapsed since the last motion.\n" - << logofs_flush; - } - - *logofs << "Proxy: FLUSH! Requesting timeout of " - << diffTs << " Ms as FD#" << fd << " has motion " - << "events to send.\n" << logofs_flush; - - #endif - - setMinTimestamp(tsMax, diffTs); - } - } - #if defined(TEST) || defined(INFO) - else - { - if (channels_[channelId] -> getType() != channel_x11 && - tokens_[token_data].remaining <= 0) - { - *logofs << "Proxy: WARNING! Descriptor FD#" << fd - << " not selected for read with " - << tokens_[token_data].remaining << " data " - << "tokens remaining.\n" << logofs_flush; - } - } - #endif - } - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "Proxy: WARNING! Disabled reading from channels.\n" - << logofs_flush; - - *logofs << "Proxy: WARNING! Congestion is " << congestion_ - << " pending " << transport_ -> pending() << " blocked " - << transport_ -> blocked() << " length " << transport_ -> - length() << ".\n" << logofs_flush; - } - #endif - - // - // Include the proxy descriptor. - // - - FD_SET(fd_, fdSet); - - if (fd_ >= fdMax) - { - fdMax = fd_ + 1; - } - - #ifdef TEST - *logofs << "Proxy: Proxy descriptor FD#" << fd_ - << " selected for read with buffer length " - << transport_ -> length() << ".\n" - << logofs_flush; - #endif - - return 1; -} - -// -// Add to the mask the file descriptors of all -// X connections to write to. -// - -int Proxy::setWriteDescriptors(fd_set *fdSet, int &fdMax, T_timestamp &tsMax) -{ - int fd = -1; - - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] != NULL) - { - fd = getFd(channelId); - - if (transports_[channelId] -> length() > 0) - { - FD_SET(fd, fdSet); - - #ifdef TEST - *logofs << "Proxy: Descriptor FD#" << fd << " selected " - << "for write with blocked " << transports_[channelId] -> - blocked() << " and length " << transports_[channelId] -> - length() << ".\n" << logofs_flush; - #endif - - if (fd >= fdMax) - { - fdMax = fd + 1; - } - } - #ifdef TEST - else - { - *logofs << "Proxy: Descriptor FD#" << fd << " not selected " - << "for write with blocked " << transports_[channelId] -> - blocked() << " and length " << transports_[channelId] -> - length() << ".\n" << logofs_flush; - } - #endif - - #if defined(TEST) || defined(INFO) - - if (transports_[channelId] -> getType() != - transport_agent && transports_[channelId] -> - length() > 0 && transports_[channelId] -> - blocked() != 1) - { - *logofs << "Proxy: PANIC! Descriptor FD#" << fd - << " has data to write but blocked flag is " - << transports_[channelId] -> blocked() - << ".\n" << logofs_flush; - - cerr << "Error" << ": Descriptor FD#" << fd - << " has data to write but blocked flag is " - << transports_[channelId] -> blocked() - << ".\n"; - - HandleCleanup(); - } - - #endif - } - } - - // - // Check if the proxy transport has data - // from a previous blocking write. - // - - if (transport_ -> blocked() == 1) - { - FD_SET(fd_, fdSet); - - #ifdef TEST - *logofs << "Proxy: Proxy descriptor FD#" - << fd_ << " selected for write. Blocked is " - << transport_ -> blocked() << " length is " - << transport_ -> length() << ".\n" - << logofs_flush; - #endif - - if (fd_ >= fdMax) - { - fdMax = fd_ + 1; - } - } - #ifdef TEST - else - { - *logofs << "Proxy: Proxy descriptor FD#" - << fd_ << " not selected for write. Blocked is " - << transport_ -> blocked() << " length is " - << transport_ -> length() << ".\n" - << logofs_flush; - } - #endif - - // - // We are entering the main select. Save - // the timestamp of the last loop so that - // we can detect the clock drifts. - // - - timeouts_.loopTs = getTimestamp(); - - return 1; -} - -int Proxy::getChannels(T_channel_type type) -{ - int channels = 0; - - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] != NULL && - (type == channel_none || - type == channels_[channelId] -> - getType())) - { - channels++; - } - } - - return channels; -} - -T_channel_type Proxy::getType(int fd) -{ - int channelId = getChannel(fd); - - if (channelId < 0 || channels_[channelId] == NULL) - { - return channel_none; - } - - return channels_[channelId] -> getType(); -} - -const char *Proxy::getTypeName(T_channel_type type) -{ - switch (type) - { - case channel_x11: - { - return "X"; - } - case channel_cups: - { - return "CUPS"; - } - case channel_smb: - { - return "SMB"; - } - case channel_media: - { - return "media"; - } - case channel_http: - { - return "HTTP"; - } - case channel_font: - { - return "font"; - } - case channel_slave: - { - return "slave"; - } - default: - { - return "unknown"; - } - } -} - -const char *Proxy::getComputerName() -{ - // - // Strangely enough, under some Windows OSes SMB - // service doesn't bind to localhost. Fall back - // to localhost if can't find computer name in - // the environment. In future we should try to - // bind to localhost and then try the other IPs. - // - - const char *hostname = NULL; - - #ifdef __CYGWIN32__ - - hostname = getenv("COMPUTERNAME"); - - #endif - - if (hostname == NULL) - { - hostname = "localhost"; - } - - return hostname; -} - -// -// Handle data from channels selected for read. -// - -int Proxy::handleRead(int &resultFds, fd_set &readSet) -{ - #ifdef DEBUG - *logofs << "Proxy: Checking descriptors selected for read.\n" - << logofs_flush; - #endif - - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - #ifdef DEBUG - *logofs << "Proxy: Looping with current channel " - << *j << ".\n" << logofs_flush; - #endif - - int fd = getFd(*j); - - if (fd >= 0 && resultFds > 0 && FD_ISSET(fd, &readSet)) - { - #ifdef DEBUG - *logofs << "Proxy: Going to read messages from FD#" - << fd << ".\n" << logofs_flush; - #endif - - int result = handleRead(fd); - - if (result < 0) - { - #ifdef TEST - *logofs << "Proxy: Failure reading messages from FD#" - << fd << ".\n" << logofs_flush; - #endif - - return -1; - } - - #ifdef DEBUG - *logofs << "Proxy: Clearing the read descriptor " - << "for FD#" << fd << ".\n" << logofs_flush; - #endif - - FD_CLR(fd, &readSet); - - resultFds--; - } - } - - if (resultFds > 0 && FD_ISSET(fd_, &readSet)) - { - #ifdef DEBUG - *logofs << "Proxy: Going to read messages from " - << "proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - if (handleRead() < 0) - { - #ifdef TEST - *logofs << "Proxy: Failure reading from proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - return -1; - } - - #ifdef DEBUG - *logofs << "Proxy: Clearing the read descriptor " - << "for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - FD_CLR(fd_, &readSet); - - resultFds--; - } - - return 1; -} - -// -// Perform flush on descriptors selected for write. -// - -int Proxy::handleFlush(int &resultFds, fd_set &writeSet) -{ - #ifdef DEBUG - *logofs << "Proxy: Checking descriptors selected for write.\n" - << logofs_flush; - #endif - - if (resultFds > 0 && FD_ISSET(fd_, &writeSet)) - { - #ifdef TEST - *logofs << "Proxy: FLUSH! Proxy descriptor FD#" << fd_ - << " reported to be writable.\n" - << logofs_flush; - #endif - - if (handleFlush() < 0) - { - #ifdef TEST - *logofs << "Proxy: Failure flushing the writable " - << "proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - return -1; - } - - #ifdef DEBUG - *logofs << "Proxy: Clearing the write descriptor " - << "for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - FD_CLR(fd_, &writeSet); - - resultFds--; - } - - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - resultFds > 0 && j != channelList.end(); j++) - { - #ifdef DEBUG - *logofs << "Proxy: Looping with current channel " - << *j << ".\n" << logofs_flush; - #endif - - int fd = getFd(*j); - - if (fd >= 0 && FD_ISSET(fd, &writeSet)) - { - #ifdef TEST - *logofs << "Proxy: X descriptor FD#" << fd - << " reported to be writable.\n" - << logofs_flush; - #endif - - // - // It can happen that, in handling reads, we - // have destroyed the buffer associated to a - // closed socket, so don't complain about - // the errors. - // - - handleFlush(fd); - - // - // Clear the descriptor from the mask so - // we don't confuse the agent if it's - // not checking only its own descriptors. - // - - #ifdef DEBUG - *logofs << "Proxy: Clearing the write descriptor " - << "for FD#" << fd << ".\n" - << logofs_flush; - #endif - - FD_CLR(fd, &writeSet); - - resultFds--; - } - } - - return 1; -} - -int Proxy::handleRead() -{ - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Decoding data from proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - // - // Decode all the available messages from - // the remote proxy until is not possible - // to read more. - // - - for (;;) - { - int result = readBuffer_.readMessage(); - - #if defined(TEST) || defined(DEBUG) || defined(INFO) - *logofs << "Proxy: Read result on proxy FD#" << fd_ - << " is " << result << ".\n" - << logofs_flush; - #endif - - if (result < 0) - { - if (shutdown_ == 0) - { - if (finish_ == 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Failure reading from the " - << "peer proxy on FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure reading from the " - << "peer proxy.\n"; - } - } - #ifdef TEST - else - { - *logofs << "Proxy: Closure of the proxy link detected " - << "after clean shutdown.\n" << logofs_flush; - } - #endif - - priority_ = 0; - finish_ = 1; - congestion_ = 0; - - return -1; - } - else if (result == 0) - { - #if defined(TEST) || defined(DEBUG) || defined(INFO) - *logofs << "Proxy: No data read from proxy FD#" - << fd_ << "\n" << logofs_flush; - #endif - - return 0; - } - - // - // We read some data from the remote. If we set - // the congestion flag because we couldn't read - // before the timeout and have tokens available, - // then reset the congestion flag. - // - - if (congestion_ == 1 && - tokens_[token_control].remaining > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Exiting congestion due to " - << "proxy data with " << tokens_[token_control].remaining - << " tokens.\n" << logofs_flush; - #endif - - congestion_ = 0; - } - - // - // Set the timestamp of the last read - // operation from the remote proxy and - // enable again showing the 'no data - // received' dialog at the next timeout. - // - - timeouts_.readTs = getTimestamp(); - - if (alert_ != 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Displacing the dialog " - << "for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - HandleAlert(DISPLACE_MESSAGE_ALERT, 1); - } - - timeouts_.alertTs = nullTimestamp(); - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Getting messages from proxy FD#" << fd_ - << " with " << readBuffer_.getLength() << " bytes " - << "in the read buffer.\n" << logofs_flush; - #endif - - unsigned int controlLength; - unsigned int dataLength; - - const unsigned char *message; - - while ((message = readBuffer_.getMessage(controlLength, dataLength)) != NULL) - { - statistics -> addFrameIn(); - - if (controlLength == 3 && *message == 0 && - *(message + 1) < code_last_tag) - { - if (handleControlFromProxy(message) < 0) - { - return -1; - } - } - else if (operation_ == operation_in_messages) - { - int channelId = inputChannel_; - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Identified message of " << dataLength - << " bytes for FD#" << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - if (channelId >= 0 && channelId < CONNECTIONS_LIMIT && - channels_[channelId] != NULL) - { - int finish = channels_[channelId] -> getFinish(); - - #ifdef WARNING - - if (finish == 1) - { - *logofs << "Proxy: WARNING! Handling data for finishing " - << "FD#" << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - } - - #endif - - // - // We need to decode all the data to preserve - // the consistency of the cache, so can't re- - // turn as soon as the first error is encount- - // ered. Check if this is the first time that - // the failure is detected. - // - - int result = channels_[channelId] -> handleWrite(message, dataLength); - - if (result < 0 && finish == 0) - { - #ifdef TEST - *logofs << "Proxy: Failed to write proxy data to FD#" - << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - if (handleFinish(channelId) < 0) - { - return -1; - } - } - - // - // Check if we have splits or motion - // events to send. - // - - setSplitTimeout(channelId); - setMotionTimeout(channelId); - } - #ifdef WARNING - else - { - *logofs << "Proxy: WARNING! Received data for " - << "invalid channel ID#" << channelId - << ".\n" << logofs_flush; - } - #endif - } - else if (operation_ == operation_in_statistics) - { - #ifdef TEST - *logofs << "Proxy: Received statistics data from remote proxy.\n" - << logofs_flush; - #endif - - if (handleStatisticsFromProxy(message, dataLength) < 0) - { - return -1; - } - - operation_ = operation_in_messages; - } - else if (operation_ == operation_in_negotiation) - { - #ifdef TEST - *logofs << "Proxy: Received new negotiation data from remote proxy.\n" - << logofs_flush; - #endif - - if (handleNegotiationFromProxy(message, dataLength) < 0) - { - return -1; - } - } - - // - // if (controlLength == 3 && *message == 0 && ...) ... - // else if (operation_ == operation_in_statistics) ... - // else if (operation_ == operation_in_messages) ... - // else if (operation_ == operation_in_negotiation) ... - // else ... - // - - else - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Unrecognized message received on proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unrecognized message received on proxy FD#" - << fd_ << ".\n"; - - return -1; - } - - } // while ((message = readBuffer_.getMessage(controlLength, dataLength)) != NULL) ... - - // - // Reset the read buffer. - // - - readBuffer_.fullReset(); - - // - // Give up if no data is readable. - // - - if (transport_ -> readable() == 0) - { - break; - } - - } // End of for (;;) ... - - return 1; -} - -int Proxy::handleControlFromProxy(const unsigned char *message) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Received message '" << DumpControl(*(message + 1)) - << "' at " << strMsTimestamp() << " with data ID#" - << (int) *(message + 2) << ".\n" << logofs_flush; - #endif - - T_channel_type channelType = channel_none; - - switch (*(message + 1)) - { - case code_switch_connection: - { - int channelId = *(message + 2); - - // - // If channel is invalid further messages will - // be ignored. The acknowledged shutdown of - // channels should prevent this. - // - - inputChannel_ = channelId; - - break; - } - case code_begin_congestion: - { - // - // Set the congestion state for the - // channel reported by the remote. - // - - int channelId = *(message + 2); - - if (channels_[channelId] != NULL) - { - congestions_[channelId] = 1; - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Received a begin congestion " - << "for channel id ID#" << channelId - << ".\n" << logofs_flush; - #endif - - if (channelId == agent_ && congestions_[agent_] != 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Forcing an update of the congestion " - << "counter with agent congested.\n" - << logofs_flush; - #endif - - statistics -> updateCongestion(-tokens_[token_control].remaining, - tokens_[token_control].limit); - } - } - #ifdef WARNING - else - { - *logofs << "Proxy: WARNING! Received a begin congestion " - << "for invalid channel id ID#" << channelId - << ".\n" << logofs_flush; - } - #endif - - break; - } - case code_end_congestion: - { - // - // Attend again to the channel. - // - - int channelId = *(message + 2); - - if (channels_[channelId] != NULL) - { - congestions_[channelId] = 0; - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Received an end congestion " - << "for channel id ID#" << channelId - << ".\n" << logofs_flush; - #endif - - if (channelId == agent_ && congestions_[agent_] != 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Forcing an update of the congestion " - << "counter with agent decongested.\n" - << logofs_flush; - #endif - - statistics -> updateCongestion(tokens_[token_control].remaining, - tokens_[token_control].limit); - } - } - #ifdef WARNING - else - { - *logofs << "Proxy: WARNING! Received an end congestion " - << "for invalid channel id ID#" << channelId - << ".\n" << logofs_flush; - } - #endif - - break; - } - case code_control_token_request: - { - T_proxy_token &token = tokens_[token_control]; - - if (handleTokenFromProxy(token, *(message + 2)) < 0) - { - return -1; - } - - break; - } - case code_split_token_request: - { - T_proxy_token &token = tokens_[token_split]; - - if (handleTokenFromProxy(token, *(message + 2)) < 0) - { - return -1; - } - - break; - } - case code_data_token_request: - { - T_proxy_token &token = tokens_[token_data]; - - if (handleTokenFromProxy(token, *(message + 2)) < 0) - { - return -1; - } - - break; - } - case code_control_token_reply: - { - T_proxy_token &token = tokens_[token_control]; - - if (handleTokenReplyFromProxy(token, *(message + 2)) < 0) - { - return -1; - } - - break; - } - case code_split_token_reply: - { - T_proxy_token &token = tokens_[token_split]; - - if (handleTokenReplyFromProxy(token, *(message + 2)) < 0) - { - return -1; - } - - break; - } - case code_data_token_reply: - { - T_proxy_token &token = tokens_[token_data]; - - if (handleTokenReplyFromProxy(token, *(message + 2)) < 0) - { - return -1; - } - - break; - } - case code_new_x_connection: - { - // - // Opening the channel is handled later. - // - - channelType = channel_x11; - - break; - } - case code_new_cups_connection: - { - channelType = channel_cups; - - break; - } - case code_new_aux_connection: - { - // - // Starting from version 1.5.0 we create real X - // connections for the keyboard channel. We need - // to refuse old auxiliary X connections because - // they would be unable to leverage the new fake - // authorization cookie. - // - - #ifdef WARNING - *logofs << "Proxy: WARNING! Can't open outdated auxiliary X " - << "channel for code " << *(message + 1) << ".\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Can't open outdated auxiliary X " - << "channel for code " << *(message + 1) << ".\n"; - - if (handleControl(code_drop_connection, *(message + 2)) < 0) - { - return -1; - } - - break; - } - case code_new_smb_connection: - { - channelType = channel_smb; - - break; - } - case code_new_media_connection: - { - channelType = channel_media; - - break; - } - case code_new_http_connection: - { - channelType = channel_http; - - break; - } - case code_new_font_connection: - { - channelType = channel_font; - - break; - } - case code_new_slave_connection: - { - channelType = channel_slave; - - break; - } - case code_drop_connection: - { - int channelId = *(message + 2); - - if (channelId >= 0 && channelId < CONNECTIONS_LIMIT && - channels_[channelId] != NULL) - { - handleDropFromProxy(channelId); - } - #ifdef WARNING - else - { - *logofs << "Proxy: WARNING! Received a drop message " - << "for invalid channel id ID#" << channelId - << ".\n" << logofs_flush; - } - #endif - - break; - } - case code_finish_connection: - { - int channelId = *(message + 2); - - if (channelId >= 0 && channelId < CONNECTIONS_LIMIT && - channels_[channelId] != NULL) - { - // - // Force the finish state on the channel. - // We can receive this message while in - // the read loop, so we only mark the - // channel for deletion. - // - - #ifdef TEST - *logofs << "Proxy: Received a finish message for FD#" - << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - handleFinishFromProxy(channelId); - } - #ifdef WARNING - else - { - *logofs << "Proxy: WARNING! Received a finish message " - << "for invalid channel id ID#" << channelId - << ".\n" << logofs_flush; - } - #endif - - break; - } - case code_finish_listeners: - { - // - // This is from the main loop. - // - - #ifdef TEST - *logofs << "Proxy: Closing down all local listeners.\n" - << logofs_flush; - #endif - - CleanupListeners(); - - finish_ = 1; - - break; - } - case code_reset_request: - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Proxy reset not supported " - << "in this version.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Proxy reset not supported " - << "in this version.\n"; - - HandleCleanup(); - } - case code_shutdown_request: - { - // - // Time to rest in peace. - // - - shutdown_ = 1; - - break; - } - case code_load_request: - { - if (handleLoadFromProxy() < 0) - { - return -1; - } - - break; - } - case code_save_request: - { - // - // Don't abort the connection - // if can't write to disk. - // - - handleSaveFromProxy(); - - break; - } - case code_statistics_request: - { - int type = *(message + 2); - - if (handleStatisticsFromProxy(type) < 0) - { - return -1; - } - - break; - } - case code_statistics_reply: - { - operation_ = operation_in_statistics; - - break; - } - case code_alert_request: - { - HandleAlert(*(message + 2), 1); - - break; - } - case code_sync_request: - { - int channelId = *(message + 2); - - if (handleSyncFromProxy(channelId) < 0) - { - return -1; - } - - break; - } - case code_sync_reply: - { - // - // We are not the one that issued - // the request. - // - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: PANIC! Received an unexpected " - << "synchronization reply.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Received an unexpected " - << "synchronization reply.\n"; - - HandleCleanup(); - } - default: - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Received bad control message number " - << (unsigned int) *(message + 1) << " with attribute " - << (unsigned int) *(message + 2) << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Received bad control message number " - << (unsigned int) *(message + 1) << " with attribute " - << (unsigned int) *(message + 2) << ".\n"; - - HandleCleanup(); - } - - } // End of switch (*(message + 1)) ... - - if (channelType == channel_none) - { - return 1; - } - - // - // Handle the channel allocation that we - // left from the main switch case. - // - - int channelId = *(message + 2); - - // - // Check if the channel has been dropped. - // - - if (channels_[channelId] != NULL && - (channels_[channelId] -> getDrop() == 1 || - channels_[channelId] -> getClosing() == 1)) - { - #ifdef TEST - *logofs << "Proxy: Dropping the descriptor FD#" - << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - handleDrop(channelId); - } - - // - // Check if the channel is in the valid - // range. - // - - int result = checkChannelMap(channelId); - - if (result >= 0) - { - result = handleNewConnectionFromProxy(channelType, channelId); - } - - if (result < 0) - { - // - // Realization of new channel failed. - // Send channel shutdown message to - // the peer proxy. - // - - if (handleControl(code_drop_connection, channelId) < 0) - { - return -1; - } - } - else - { - int fd = getFd(channelId); - - if (getReadable(fd) > 0) - { - #ifdef TEST - *logofs << "Proxy: Trying to read immediately " - << "from descriptor FD#" << fd << ".\n" - << logofs_flush; - #endif - - if (handleRead(fd) < 0) - { - return -1; - } - } - #ifdef TEST - *logofs << "Proxy: Nothing to read immediately " - << "from descriptor FD#" << fd << ".\n" - << logofs_flush; - #endif - } - - return 1; -} - -int Proxy::handleRead(int fd, const char *data, int size) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Handling data for connection on FD#" - << fd << ".\n" << logofs_flush; - #endif - - if (canRead(fd) == 0) - { - #if defined(TEST) || defined(INFO) - - if (getChannel(fd) < 0) - { - *logofs << "Proxy: PANIC! Can't read from invalid FD#" - << fd << ".\n" << logofs_flush; - - HandleCleanup(); - } - else - { - *logofs << "Proxy: WARNING! Read method called for FD#" - << fd << " but operation is not possible.\n" - << logofs_flush; - } - - #endif - - return 0; - } - - int channelId = getChannel(fd); - - // - // Let the channel object read all the new data from - // its file descriptor, isolate messages, compress - // those messages, and append the compressed form to - // the encode buffer. - // - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Reading messages from FD#" << fd - << " channel ID#" << channelId << ".\n" - << logofs_flush; - #endif - - int result = channels_[channelId] -> handleRead(encodeBuffer_, (const unsigned char *) data, - (unsigned int) size); - - // - // Even in the case of a failure, write the produced - // data to the proxy connection. To keep the stores - // synchronized, the remote side needs to decode any - // message encoded by this side, also if the X socket - // was closed in the meanwhile. If this is the case, - // the decompressed output will be silently discarded. - // - - if (result < 0) - { - #ifdef TEST - *logofs << "Proxy: Failed to read data from connection FD#" - << fd << " channel ID#" << channelId << ".\n" - << logofs_flush; - #endif - - if (handleFinish(channelId) < 0) - { - return -1; - } - } - - // - // Check if there are new splits or - // motion events to send. - // - - setSplitTimeout(channelId); - setMotionTimeout(channelId); - - return 1; -} - -int Proxy::handleEvents() -{ - #ifdef TEST - *logofs << "Proxy: Going to check the events on channels.\n" - << logofs_flush; - #endif - - // - // Check if we can safely write to the - // proxy link. - // - - int read = isTimeToRead(); - - // - // Loop on channels and send the pending - // events. We must copy the list because - // channels can be removed in the middle - // of the loop. - // - - T_list channelList = activeChannels_.copyList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] == NULL) - { - continue; - } - - // - // Check if we need to drop the channel. - // - - if (channels_[channelId] -> getDrop() == 1 || - channels_[channelId] -> getClosing() == 1) - { - #ifdef TEST - *logofs << "Proxy: Dropping the descriptor FD#" - << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - if (handleDrop(channelId) < 0) - { - return -1; - } - - continue; - } - else if (channels_[channelId] -> getFinish() == 1) - { - #ifdef TEST - *logofs << "Proxy: Skipping finishing " - << "descriptor FD#" << getFd(channelId) - << " channel ID#" << channelId << ".\n" - << logofs_flush; - #endif - - continue; - } - - // - // If the proxy link or the channel is - // in congestion state, don't handle - // the further events. - // - - if (read == 0 || congestions_[channelId] == 1) - { - #ifdef TEST - - if (read == 0) - { - *logofs << "Proxy: Can't handle events for FD#" - << getFd(channelId) << " channel ID#" - << channelId << " with proxy not available.\n" - << logofs_flush; - } - else - { - *logofs << "Proxy: Can't handle events for FD#" - << getFd(channelId) << " channel ID#" - << channelId << " with channel congested.\n" - << logofs_flush; - } - - #endif - - continue; - } - - // - // Handle the timeouts on the channel - // operations. - // - - int result = 0; - - // - // Handle the motion events. - // - - if (result >= 0 && channels_[channelId] -> needMotion() == 1) - { - if (isTimeToMotion() == 1) - { - #if defined(TEST) || defined(INFO) || defined(FLUSH) - - *logofs << "Proxy: FLUSH! Motion timeout expired after " - << diffTimestamp(timeouts_.motionTs, getTimestamp()) - << " Ms.\n" << logofs_flush; - - #endif - - result = channels_[channelId] -> handleMotion(encodeBuffer_); - - #ifdef TEST - - if (result < 0) - { - *logofs << "Proxy: Failed to handle motion events for FD#" - << getFd(channelId) << " channel ID#" << channelId - << ".\n" << logofs_flush; - } - - #endif - - timeouts_.motionTs = nullTimestamp(); - - setMotionTimeout(channelId); - } - #if defined(TEST) || defined(INFO) - else if (isTimestamp(timeouts_.motionTs) == 1) - { - *logofs << "Proxy: Running with " - << diffTimestamp(timeouts_.motionTs, getTimestamp()) - << " Ms elapsed since the last motion.\n" - << logofs_flush; - } - #endif - } - - if (result >= 0 && channels_[channelId] -> needSplit() == 1) - { - // - // Check if it is time to send more splits - // and how many bytes are going to be sent. - // - - if (isTimeToSplit() == 1) - { - #if defined(TEST) || defined(INFO) || defined(SPLIT) - *logofs << "Proxy: SPLIT! Split timeout expired after " - << diffTimestamp(timeouts_.splitTs, getTimestamp()) - << " Ms.\n" << logofs_flush; - #endif - - #if defined(TEST) || defined(INFO) || defined(SPLIT) - - *logofs << "Proxy: SPLIT! Encoding splits for FD#" - << getFd(channelId) << " at " << strMsTimestamp() - << " with " << clientStore_ -> getSplitTotalStorageSize() - << " total bytes and " << control -> SplitDataPacketLimit - << " bytes " << "to write.\n" - << logofs_flush; - - #endif - - result = channels_[channelId] -> handleSplit(encodeBuffer_); - - #ifdef TEST - - if (result < 0) - { - *logofs << "Proxy: Failed to handle splits for FD#" - << getFd(channelId) << " channel ID#" << channelId - << ".\n" << logofs_flush; - } - - #endif - - timeouts_.splitTs = nullTimestamp(); - - setSplitTimeout(channelId); - } - #if defined(TEST) || defined(INFO) || defined(SPLIT) - else if (channels_[channelId] -> needSplit() == 1 && - isTimestamp(timeouts_.splitTs) == 0) - { - *logofs << "Proxy: SPLIT! WARNING! Channel for FD#" - << getFd(channelId) << " has split to send but " - << "there is no timeout.\n" << logofs_flush; - } - else if (isTimestamp(timeouts_.splitTs) == 1) - { - *logofs << "Proxy: SPLIT! Running with " - << diffTimestamp(timeouts_.splitTs, getTimestamp()) - << " Ms elapsed since the last split.\n" - << logofs_flush; - } - #endif - } - - if (result < 0) - { - #ifdef TEST - *logofs << "Proxy: Error handling events for FD#" - << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - if (handleFinish(channelId) < 0) - { - return -1; - } - } - } - - return 1; -} - -int Proxy::handleFrame(T_frame_type type) -{ - // - // Write any outstanding control message, followed by the - // content of the encode buffer, to the proxy transport. - // - // This code assumes that the encode buffer data is at an - // offset several bytes from start of the buffer, so that - // the length header and any necessary control bytes can - // be inserted in front of the data already in the buffer. - // This is the easiest way to encapsulate header and data - // together in a single frame. - // - // The way framing is implemented is very efficient but - // inherently limited and does not allow for getting the - // best performance, especially when running over a fast - // link. Framing should be rewritten to include the length - // of the packets in a fixed size header and, possibly, - // to incapsulate the control messages and the channel's - // data in a pseudo X protocol message, so that the proxy - // itself would be treated like any other channel. - // - - #if defined(TEST) || defined(INFO) - - if (congestion_ == 1) - { - // - // This can happen because there may be control - // messages to send, like a proxy shutdown mes- - // sage or a statistics request. All the other - // cases should be considered an error. - // - - #ifdef WARNING - *logofs << "Proxy: WARNING! Data is to be sent while " - << "congestion is " << congestion_ << ".\n" - << logofs_flush; - #endif - } - - #endif - - // - // Check if there is any data available on - // the socket. Recent Linux kernels are very - // picky. They require that we read often or - // they assume that the process is non-inter- - // active. - // - - if (handleAsyncEvents() < 0) - { - return -1; - } - - // - // Check if this is a ping, not a data frame. - // - - if (type == frame_ping) - { - if (handleToken(frame_ping) < 0) - { - return -1; - } - } - - unsigned int dataLength = encodeBuffer_.getLength(); - - #ifdef DEBUG - *logofs << "Proxy: Data length is " << dataLength - << " control length is " << controlLength_ - << ".\n" << logofs_flush; - #endif - - if (dataLength > 0) - { - // - // If this is a generic channel we need - // to add the completion bits. Data can - // also have been encoded because of a - // statistics request, even if no output - // channel was currently selected. - // - - if (outputChannel_ != -1) - { - #if defined(TEST) || defined(INFO) - - if (channels_[outputChannel_] == NULL) - { - *logofs << "Proxy: PANIC! A new frame was requested " - << "but the channel is invalid.\n" - << logofs_flush; - - HandleCleanup(); - } - - #endif - - channels_[outputChannel_] -> handleCompletion(encodeBuffer_); - - dataLength = encodeBuffer_.getLength(); - } - } - else if (controlLength_ == 0) - { - #if defined(TEST) || defined(INFO) - - *logofs << "Proxy: PANIC! A new frame was requested " - << "but there is no data to write.\n" - << logofs_flush; - - HandleCleanup(); - - #endif - - return 0; - } - - #ifdef DEBUG - *logofs << "Proxy: Data length is now " << dataLength - << " control length is " << controlLength_ - << ".\n" << logofs_flush; - #endif - - // - // Check if this frame needs to carry a new - // token request. - // - - if (type == frame_data) - { - if (handleToken(frame_data) < 0) - { - return -1; - } - } - - #ifdef DEBUG - *logofs << "Proxy: Adding a new frame for the remote proxy.\n" - << logofs_flush; - #endif - - unsigned char temp[5]; - - unsigned int lengthLength = 0; - unsigned int shift = dataLength; - - while (shift) - { - temp[lengthLength++] = (unsigned char) (shift & 0x7f); - - shift >>= 7; - } - - unsigned char *data = encodeBuffer_.getData(); - - unsigned char *outputMessage = data - (controlLength_ + lengthLength); - - unsigned char *nextDest = outputMessage; - - for (int i = 0; i < controlLength_; i++) - { - *nextDest++ = controlCodes_[i]; - } - - for (int j = lengthLength - 1; j > 0; j--) - { - *nextDest++ = (temp[j] | 0x80); - } - - if (lengthLength) - { - *nextDest++ = temp[0]; - } - - unsigned int outputLength = dataLength + controlLength_ + lengthLength; - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Produced plain output for " << dataLength << "+" - << controlLength_ << "+" << lengthLength << " out of " - << outputLength << " bytes.\n" << logofs_flush; - #endif - - #if defined(TEST) || defined(INFO) || defined(FLUSH) || defined(TIME) - - T_timestamp nowTs = getTimestamp(); - - *logofs << "Proxy: FLUSH! Immediate with blocked " << transport_ -> - blocked() << " length " << transport_ -> length() - << " new " << outputLength << " flushable " << transport_ -> - flushable() << " tokens " << tokens_[token_control].remaining - << " after " << diffTimestamp(timeouts_.writeTs, nowTs) - << " Ms.\n" << logofs_flush; - - *logofs << "Proxy: FLUSH! Immediate flush to proxy FD#" << fd_ - << " of " << outputLength << " bytes at " << strMsTimestamp() - << " with priority " << priority_ << ".\n" << logofs_flush; - - *logofs << "Proxy: FLUSH! Current bitrate is " - << statistics -> getBitrateInShortFrame() << " with " - << statistics -> getBitrateInLongFrame() << " in the " - << "long frame and top " << statistics -> - getTopBitrate() << ".\n" << logofs_flush; - #endif - - statistics -> addWriteOut(); - - int result = transport_ -> write(write_immediate, outputMessage, outputLength); - - #ifdef TIME - - if (diffTimestamp(timeouts_.writeTs, nowTs) > 50) - { - *logofs << "Proxy: WARNING! TIME! Data written to proxy FD#" - << fd_ << " at " << strMsTimestamp() << " after " - << diffTimestamp(timeouts_.writeTs, nowTs) - << " Ms.\n" << logofs_flush; - } - - #endif - - #ifdef DUMP - *logofs << "Proxy: Sent " << outputLength << " bytes of data " - << "with checksum "; - - DumpChecksum(outputMessage, outputLength); - - *logofs << " on proxy FD#" << fd_ << ".\n" << logofs_flush; - #endif - - #ifdef DUMP - *logofs << "Proxy: Partial checksums are:\n"; - - DumpBlockChecksums(outputMessage, outputLength, 256); - - *logofs << logofs_flush; - #endif - - // - // Clean up the encode buffer and - // bring it to the initial size. - // - - encodeBuffer_.fullReset(); - - // - // Close the connection if we got - // an error. - // - - if (result < 0) - { - #ifdef TEST - *logofs << "Proxy: Failed write to proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - return -1; - } - - // - // Account for the data frame and the - // framing overhead. - // - - if (dataLength > 0) - { - statistics -> addFrameOut(); - } - - statistics -> addFramingBits((controlLength_ + lengthLength) << 3); - - controlLength_ = 0; - - // - // Reset all buffers, counters and the - // priority flag. - // - - handleResetFlush(); - - // - // Check if more data became available - // after writing. - // - - if (handleAsyncEvents() < 0) - { - return -1; - } - - // - // Drain the proxy link if we are in - // congestion state. - // - // if (needDrain() == 1 && draining_ == 0) - // { - // if (handleDrain() < 0) - // { - // return -1; - // } - // } - // - - return result; -} - -int Proxy::handleFlush() -{ - // - // We can have data in the encode buffer or - // control bytes to send. In the case make - // up a new frame. - // - - if (encodeBuffer_.getLength() + controlLength_ > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Flushing data in the encode buffer.\n" - << logofs_flush; - #endif - - priority_ = 1; - - if (handleFrame(frame_data) < 0) - { - return -1; - } - } - - // - // Check if we have something to write. - // - - if (transport_ -> length() + transport_ -> flushable() == 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Nothing else to flush for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - return 0; - } - - #if defined(TEST) || defined(INFO) - - if (transport_ -> blocked() == 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Proxy descriptor FD#" << fd_ - << " has data to flush but the transport " - << "is not blocked.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Proxy descriptor FD#" << fd_ - << " has data to flush but the transport " - << "is not blocked.\n"; - - HandleCleanup(); - } - - #endif - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "Proxy: FLUSH! Deferred with blocked " << transport_ -> - blocked() << " length " << transport_ -> length() - << " flushable " << transport_ -> flushable() << " tokens " - << tokens_[token_control].remaining << ".\n" - << logofs_flush; - - *logofs << "Proxy: FLUSH! Deferred flush to proxy FD#" << fd_ - << " of " << transport_ -> length() + transport_ -> - flushable() << " bytes at " << strMsTimestamp() - << " with priority " << priority_ << ".\n" - << logofs_flush; - - *logofs << "Proxy: FLUSH! Current bitrate is " - << statistics -> getBitrateInShortFrame() << " with " - << statistics -> getBitrateInLongFrame() << " in the " - << "long frame and top " << statistics -> - getTopBitrate() << ".\n" << logofs_flush; - #endif - - statistics -> addWriteOut(); - - int result = transport_ -> flush(); - - if (result < 0) - { - return -1; - } - - // - // Reset the counters and update the - // timestamp of the last write. - // - - handleResetFlush(); - - return result; -} - -int Proxy::handleDrain() -{ - // - // If the proxy is run in the same process - // as SSH, we can't block or the program - // would not have a chance to read or write - // its data. - // - - if (control -> LinkEncrypted == 1) - { - return 0; - } - - if (needDrain() == 0 || draining_ == 1) - { - #if defined(TEST) || defined(INFO) - - if (draining_ == 1) - { - *logofs << "Proxy: WARNING! Already draining proxy FD#" - << fd_ << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - } - else - { - *logofs << "Proxy: WARNING! No need to drain proxy FD#" - << fd_ << " with congestion " << congestion_ - << " length " << transport_ -> length() - << " and blocked " << transport_ -> blocked() - << ".\n" << logofs_flush; - } - - #endif - - return 0; - } - - draining_ = 1; - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Going to drain the proxy FD#" << fd_ - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - int timeout = control -> PingTimeout / 2; - - T_timestamp startTs = getNewTimestamp(); - - T_timestamp nowTs = startTs; - - int remaining; - int result; - - // - // Keep draining the proxy socket while - // reading the incoming messages until - // the timeout is expired. - // - - for (;;) - { - remaining = timeout - diffTimestamp(startTs, nowTs); - - if (remaining <= 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Timeout raised while draining " - << "FD#" << fd_ << " at " << strMsTimestamp() - << " after " << diffTimestamp(startTs, nowTs) - << " Ms.\n" << logofs_flush; - #endif - - result = 0; - - goto ProxyDrainEnd; - } - - if (transport_ -> length() > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Trying to write to FD#" << fd_ - << " at " << strMsTimestamp() << " with length " - << transport_ -> length() << " and " - << remaining << " Ms remaining.\n" - << logofs_flush; - #endif - - result = transport_ -> drain(0, remaining); - - if (result == -1) - { - result = -1; - - goto ProxyDrainEnd; - } - else if (result == 0 && transport_ -> readable() > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Decoding more data from proxy FD#" - << fd_ << " at " << strMsTimestamp() << " with " - << transport_ -> length() << " bytes to write and " - << transport_ -> readable() << " readable.\n" - << logofs_flush; - #endif - - if (handleRead() < 0) - { - result = -1; - - goto ProxyDrainEnd; - } - } - #if defined(TEST) || defined(INFO) - else if (result == 1) - { - *logofs << "Proxy: Transport for proxy FD#" << fd_ - << " drained down to " << transport_ -> length() - << " bytes.\n" << logofs_flush; - } - #endif - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Waiting for more data from proxy " - << "FD#" << fd_ << " at " << strMsTimestamp() - << " with " << remaining << " Ms remaining.\n" - << logofs_flush; - #endif - - - result = transport_ -> wait(remaining); - - if (result == -1) - { - result = -1; - - goto ProxyDrainEnd; - } - else if (result > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Decoding more data from proxy FD#" - << fd_ << " at " << strMsTimestamp() << " with " - << transport_ -> readable() << " bytes readable.\n" - << logofs_flush; - #endif - - if (handleRead() < 0) - { - result = -1; - - goto ProxyDrainEnd; - } - } - } - - // - // Check if we finally got the tokens - // that would allow us to come out of - // the congestion state. - // - - if (needDrain() == 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Got decongestion for proxy FD#" - << fd_ << " at " << strMsTimestamp() << " after " - << diffTimestamp(startTs, getTimestamp()) - << " Ms.\n" << logofs_flush; - #endif - - result = 1; - - goto ProxyDrainEnd; - } - - nowTs = getNewTimestamp(); - } - -ProxyDrainEnd: - - draining_ = 0; - - return result; -} - -int Proxy::handleFlush(int fd) -{ - int channelId = getChannel(fd); - - if (channelId < 0 || channels_[channelId] == NULL) - { - #ifdef TEST - *logofs << "Proxy: WARNING! Skipping flush on invalid " - << "descriptor FD#" << fd << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - return 0; - } - else if (channels_[channelId] -> getFinish() == 1) - { - #ifdef TEST - *logofs << "Proxy: Skipping flush on finishing " - << "descriptor FD#" << fd << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - return 0; - } - - #ifdef TEST - *logofs << "Proxy: Going to flush FD#" << fd - << " with blocked " << transports_[channelId] -> blocked() - << " length " << transports_[channelId] -> length() - << ".\n" << logofs_flush; - #endif - - if (channels_[channelId] -> handleFlush() < 0) - { - #ifdef TEST - *logofs << "Proxy: Failed to flush data to FD#" - << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - handleFinish(channelId); - - return -1; - } - - return 1; -} - -int Proxy::handleStatistics(int type, ostream *stream) -{ - if (stream == NULL || control -> EnableStatistics == 0) - { - #ifdef WARNING - *logofs << "Proxy: WARNING! Cannot produce statistics " - << " for proxy FD#" << fd_ << ". Invalid settings " - << "for statistics or stream.\n" << logofs_flush; - #endif - - return 0; - } - else if (currentStatistics_ != NULL) - { - // - // Need to update the stream pointer as the - // previous one could have been destroyed. - // - - #ifdef WARNING - *logofs << "Proxy: WARNING! Replacing stream while producing " - << "statistics in stream at " << currentStatistics_ - << " for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - } - - currentStatistics_ = stream; - - // - // Get statistics of remote peer. - // - - if (handleControl(code_statistics_request, type) < 0) - { - return -1; - } - - return 1; -} - -int Proxy::handleStatisticsFromProxy(int type) -{ - if (needFlush() == 1) - { - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "Proxy: WARNING! Data for the previous " - << "channel ID#" << outputChannel_ - << " flushed in statistics.\n" - << logofs_flush; - #endif - - if (handleFrame(frame_data) < 0) - { - return -1; - } - } - - if (control -> EnableStatistics == 1) - { - // - // Allocate a buffer for the output. - // - - char *buffer = new char[STATISTICS_LENGTH]; - - *buffer = '\0'; - - if (control -> ProxyMode == proxy_client) - { - #ifdef TEST - *logofs << "Proxy: Producing " - << (type == TOTAL_STATS ? "total" : "partial") - << " client statistics for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - statistics -> getClientProtocolStats(type, buffer); - - statistics -> getClientOverallStats(type, buffer); - } - else - { - #ifdef TEST - *logofs << "Proxy: Producing " - << (type == TOTAL_STATS ? "total" : "partial") - << " server statistics for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - statistics -> getServerProtocolStats(type, buffer); - } - - if (type == PARTIAL_STATS) - { - statistics -> resetPartialStats(); - } - - unsigned int length = strlen((char *) buffer) + 1; - - encodeBuffer_.encodeValue(type, 8); - - encodeBuffer_.encodeValue(length, 32); - - #ifdef TEST - *logofs << "Proxy: Encoding " << length - << " bytes of statistics data for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - encodeBuffer_.encodeMemory((unsigned char *) buffer, length); - - // - // Account statistics data as framing bits. - // - - statistics -> addFramingBits(length << 3); - - delete [] buffer; - } - else - { - #ifdef WARNING - *logofs << "Proxy: WARNING! Got statistics request " - << "but local statistics are disabled.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Got statistics request " - << "but local statistics are disabled.\n"; - - type = NO_STATS; - - encodeBuffer_.encodeValue(type, 8); - - #ifdef TEST - *logofs << "Proxy: Sending error code to remote proxy on FD#" - << fd_ << ".\n" << logofs_flush; - #endif - } - - // - // The next write will flush the statistics - // data and the control message. - // - - if (handleControl(code_statistics_reply, type) < 0) - { - return -1; - } - - return 1; -} - -int Proxy::handleStatisticsFromProxy(const unsigned char *message, unsigned int length) -{ - if (currentStatistics_ == NULL) - { - #ifdef WARNING - *logofs << "Proxy: WARNING! Unexpected statistics data received " - << "from remote proxy on FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Unexpected statistics data received " - << "from remote proxy.\n"; - - return 0; - } - - // - // Allocate the decode buffer and at least - // the 'type' field to see if there was an - // error. - // - - DecodeBuffer decodeBuffer(message, length); - - unsigned int type; - - decodeBuffer.decodeValue(type, 8); - - if (type == NO_STATS) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Couldn't get statistics from remote " - << "proxy on FD#" << fd_ << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Couldn't get statistics from remote proxy.\n"; - } - else if (type != TOTAL_STATS && type != PARTIAL_STATS) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Cannot produce statistics " - << "with qualifier '" << type << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Cannot produce statistics " - << "with qualifier '" << type << "'.\n"; - - return -1; - } - else - { - unsigned int size; - - decodeBuffer.decodeValue(size, 32); - - char *buffer = new char[STATISTICS_LENGTH]; - - *buffer = '\0'; - - if (control -> EnableStatistics == 1) - { - if (control -> ProxyMode == proxy_client) - { - #ifdef TEST - *logofs << "Proxy: Finalizing " - << (type == TOTAL_STATS ? "total" : "partial") - << " client statistics for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - statistics -> getClientCacheStats(type, buffer); - - #ifdef TEST - *logofs << "Proxy: Decoding " << size - << " bytes of statistics data for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - strncat(buffer, (char *) decodeBuffer.decodeMemory(size), size); - - statistics -> getClientProtocolStats(type, buffer); - - statistics -> getClientOverallStats(type, buffer); - } - else - { - #ifdef TEST - *logofs << "Proxy: Finalizing " - << (type == TOTAL_STATS ? "total" : "partial") - << " server statistics for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - statistics -> getServerCacheStats(type, buffer); - - statistics -> getServerProtocolStats(type, buffer); - - #ifdef TEST - *logofs << "Proxy: Decoding " << size - << " bytes of statistics data for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - strncat(buffer, (char *) decodeBuffer.decodeMemory(size), size); - } - - if (type == PARTIAL_STATS) - { - statistics -> resetPartialStats(); - } - - *currentStatistics_ << buffer; - - // - // Mark the end of text to help external parsing. - // - - *currentStatistics_ << '\4'; - - *currentStatistics_ << flush; - } - else - { - // - // It can be that statistics were enabled at the time - // we issued the request (otherwise we could not have - // set the stream), but now they have been disabled - // by user. We must decode statistics data if we want - // to keep the connection. - // - - #ifdef TEST - *logofs << "Proxy: Discarding " << size - << " bytes of statistics data for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - strncat(buffer, (char *) decodeBuffer.decodeMemory(size), size); - } - - delete [] buffer; - } - - currentStatistics_ = NULL; - - return 1; -} - -int Proxy::handleNegotiation(const unsigned char *message, unsigned int length) -{ - #ifdef PANIC - *logofs << "Proxy: PANIC! Writing data during proxy " - << "negotiation is not implemented.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Writing data during proxy " - << "negotiation is not implemented.\n"; - - return -1; -} - -int Proxy::handleNegotiationFromProxy(const unsigned char *message, unsigned int length) -{ - #ifdef PANIC - *logofs << "Proxy: PANIC! Reading data during proxy " - << "negotiation is not implemented.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Reading data during proxy " - << "negotiation is not implemented.\n"; - - return -1; -} - -int Proxy::handleAlert(int alert) -{ - if (handleControl(code_alert_request, alert) < 0) - { - return -1; - } - - return 1; -} - -int Proxy::handleCloseConnection(int clientFd) -{ - int channelId = getChannel(clientFd); - - if (channels_[channelId] != NULL && - channels_[channelId] -> getFinish() == 0) - { - #ifdef TEST - *logofs << "Proxy: Closing down the channel for FD#" - << clientFd << ".\n" << logofs_flush; - #endif - - if (handleFinish(channelId) < 0) - { - return -1; - } - - return 1; - } - - return 0; -} - -int Proxy::handleCloseAllXConnections() -{ - #ifdef TEST - *logofs << "Proxy: Closing down any remaining X channel.\n" - << logofs_flush; - #endif - - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] != NULL && - channels_[channelId] -> getType() == channel_x11 && - channels_[channelId] -> getFinish() == 0) - { - #ifdef TEST - *logofs << "Proxy: Closing down the channel for FD#" - << getFd(channelId) << ".\n" << logofs_flush; - #endif - - if (handleFinish(channelId) < 0) - { - return -1; - } - } - } - - return 1; -} - -int Proxy::handleCloseAllListeners() -{ - // Since ProtoStep7 (#issue 108) - if (finish_ == 0) - { - #ifdef TEST - *logofs << "Proxy: Closing down all remote listeners.\n" - << logofs_flush; - #endif - - if (handleControl(code_finish_listeners) < 0) - { - return -1; - } - - finish_ = 1; - } - - return 1; -} - -void Proxy::handleResetAlert() -{ - if (alert_ != 0) - { - #ifdef TEST - *logofs << "Proxy: The proxy alert '" << alert_ - << "' was displaced.\n" << logofs_flush; - #endif - - alert_ = 0; - } - - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] != NULL) - { - channels_[channelId] -> handleResetAlert(); - } - } -} - -int Proxy::handleFinish(int channelId) -{ - // - // Send any outstanding encoded data and - // do any finalization needed on the - // channel. - // - - if (needFlush(channelId) == 1) - { - if (channels_[channelId] -> getFinish() == 1) - { - #ifdef WARNING - *logofs << "Proxy: WARNING! The finishing channel ID#" - << channelId << " has data to flush.\n" - << logofs_flush; - #endif - } - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "Proxy: WARNING! Flushing data for the " - << "finishing channel ID#" << channelId - << ".\n" << logofs_flush; - #endif - - if (handleFrame(frame_data) < 0) - { - return -1; - } - } - - // - // Reset the congestion state and the - // timeouts, if needed. - // - - congestions_[channelId] = 0; - - setSplitTimeout(channelId); - setMotionTimeout(channelId); - - if (channels_[channelId] -> getFinish() == 0) - { - channels_[channelId] -> handleFinish(); - - // - // Force a failure in the case somebody - // would try to read from the channel. - // - - shutdown(getFd(channelId), SHUT_RD); - - // - // If the failure was not originated by - // the remote, send a channel shutdown - // message. - // - - if (channels_[channelId] -> getClosing() == 0) - { - #ifdef TEST - *logofs << "Proxy: Finishing channel for FD#" - << getFd(channelId) << " channel ID#" - << channelId << " because of failure.\n" - << logofs_flush; - #endif - - if (handleControl(code_finish_connection, channelId) < 0) - { - return -1; - } - } - } - - return 1; -} - -int Proxy::handleFinishFromProxy(int channelId) -{ - // - // Check if this channel has pending - // data to send. - // - - if (needFlush(channelId) == 1) - { - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "Proxy: WARNING! Flushing data for the " - << "finishing channel ID#" << channelId - << ".\n" << logofs_flush; - #endif - - if (handleFrame(frame_data) < 0) - { - return -1; - } - } - - // - // Mark the channel. We will free its - // resources at the next loop and will - // send the drop message to the remote. - // - - if (channels_[channelId] -> getClosing() == 0) - { - #ifdef TEST - *logofs << "Proxy: Marking channel for FD#" - << getFd(channelId) << " channel ID#" - << channelId << " as closing.\n" - << logofs_flush; - #endif - - channels_[channelId] -> handleClosing(); - } - - if (channels_[channelId] -> getFinish() == 0) - { - #ifdef TEST - *logofs << "Proxy: Finishing channel for FD#" - << getFd(channelId) << " channel ID#" - << channelId << " because of proxy.\n" - << logofs_flush; - #endif - - channels_[channelId] -> handleFinish(); - } - - if (handleFinish(channelId) < 0) - { - return -1; - } - - return 1; -} - -int Proxy::handleDropFromProxy(int channelId) -{ - // - // Only mark the channel. - // - - #ifdef TEST - *logofs << "Proxy: Marking channel for FD#" - << getFd(channelId) << " channel ID#" - << channelId << " as being dropped.\n" - << logofs_flush; - #endif - - if (channels_[channelId] -> getDrop() == 0) - { - channels_[channelId] -> handleDrop(); - } - - return 1; -} - -// -// Close the channel and deallocate all its -// resources. -// - -int Proxy::handleDrop(int channelId) -{ - // - // Check if this channel has pending - // data to send. - // - - if (needFlush(channelId) == 1) - { - if (channels_[channelId] -> getFinish() == 1) - { - #ifdef WARNING - *logofs << "Proxy: WARNING! The dropping channel ID#" - << channelId << " has data to flush.\n" - << logofs_flush; - #endif - } - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "Proxy: WARNING! Flushing data for the " - << "dropping channel ID#" << channelId - << ".\n" << logofs_flush; - #endif - - if (handleFrame(frame_data) < 0) - { - return -1; - } - } - - #ifdef TEST - *logofs << "Proxy: Dropping channel for FD#" - << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - if (channels_[channelId] -> getFinish() == 0) - { - #ifdef WARNING - *logofs << "Proxy: WARNING! The channel for FD#" - << getFd(channelId) << " channel ID#" - << channelId << " was not marked as " - << "finishing.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": The channel for FD#" - << getFd(channelId) << " channel ID#" - << channelId << " was not marked as " - << "finishing.\n"; - - channels_[channelId] -> handleFinish(); - } - - // - // Send the channel shutdown message - // to the peer proxy. - // - - if (channels_[channelId] -> getClosing() == 1) - { - if (handleControl(code_drop_connection, channelId) < 0) - { - return -1; - } - } - - // - // Get rid of the channel. - // - - if (channels_[channelId] -> getType() != channel_x11) - { - #ifdef TEST - *logofs << "Proxy: Closed connection to " - << getTypeName(channels_[channelId] -> getType()) - << " server.\n" << logofs_flush; - #endif - - cerr << "Info" << ": Closed connection to " - << getTypeName(channels_[channelId] -> getType()) - << " server.\n"; - } - - delete channels_[channelId]; - channels_[channelId] = NULL; - - cleanupChannelMap(channelId); - - // - // Get rid of the transport. - // - - deallocateTransport(channelId); - - congestions_[channelId] = 0; - - decreaseChannels(channelId); - - // - // Check if the channel was the - // one currently selected for - // output. - // - - if (outputChannel_ == channelId) - { - outputChannel_ = -1; - } - - return 1; -} - -// -// Send an empty message to the remote peer -// to verify if the link is alive and let -// the remote proxy detect a congestion. -// - -int Proxy::handlePing() -{ - T_timestamp nowTs = getTimestamp(); - - #if defined(DEBUG) || defined(PING) - - *logofs << "Proxy: Checking ping at " - << strMsTimestamp(nowTs) << logofs_flush; - - *logofs << " with last loop at " - << strMsTimestamp(timeouts_.loopTs) << ".\n" - << logofs_flush; - - *logofs << "Proxy: Last bytes in at " - << strMsTimestamp(timeouts_.readTs) << logofs_flush; - - *logofs << " last bytes out at " - << strMsTimestamp(timeouts_.writeTs) << ".\n" - << logofs_flush; - - *logofs << "Proxy: Last ping at " - << strMsTimestamp(timeouts_.pingTs) << ".\n" - << logofs_flush; - - #endif - - // - // Be sure we take into account any clock drift. This - // can be caused by the user changing the system timer - // or by small adjustments introduced by the operating - // system making the clock go backward. - // - - if (checkDiffTimestamp(timeouts_.loopTs, nowTs) == 0) - { - #ifdef WARNING - *logofs << "Proxy: WARNING! Detected drift in system " - << "timer. Resetting to current time.\n" - << logofs_flush; - #endif - - timeouts_.pingTs = nowTs; - timeouts_.readTs = nowTs; - timeouts_.writeTs = nowTs; - } - - // - // Check timestamp of last read from remote proxy. It can - // happen that we stayed in the main loop long enough to - // have idle timeout expired, for example if the proxy was - // stopped and restarted or because of an extremely high - // load of the system. In this case we don't complain if - // there is something new to read from the remote. - // - - int diffIn = diffTimestamp(timeouts_.readTs, nowTs); - - if (diffIn >= (control -> PingTimeout * 2) - - control -> LatencyTimeout) - { - // - // Force a read to detect whether the remote proxy - // aborted the connection. - // - - int result = handleRead(); - - if (result < 0) - { - #if defined(TEST) || defined(INFO) || defined(PING) - *logofs << "Proxy: WARNING! Detected shutdown waiting " - << "for the ping after " << diffIn / 1000 - << " seconds.\n" << logofs_flush; - #endif - - return -1; - } - else if (result > 0) - { - diffIn = diffTimestamp(timeouts_.readTs, nowTs); - - if (handleFlush() < 0) - { - return -1; - } - } - } - - if (diffIn >= (control -> PingTimeout * 2) - - control -> LatencyTimeout) - { - #if defined(TEST) || defined(INFO) || defined(PING) - *logofs << "Proxy: Detected congestion at " - << strMsTimestamp() << " with " << diffIn / 1000 - << " seconds since the last read.\n" - << logofs_flush; - #endif - - // - // There are two types of proxy congestion. The first, - // affecting the ability of the proxy to write the - // encoded data to the network, is controlled by the - // congestion_ flag. The flag is raised when no data - // is received from the remote proxy within a timeout. - // On the X client side, the flag is also raised when - // the proxy runs out of tokens. - // - - if (control -> ProxyMode == proxy_server) - { - // - // At X server side we must return to read data - // from the channels after a while, because we - // need to give a chance to the channel to read - // the key sequence CTRL+ALT+SHIFT+ESC. - // - - if (congestion_ == 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Forcibly entering congestion due to " - << "timeout with " << tokens_[token_control].remaining - << " tokens.\n" << logofs_flush; - #endif - - congestion_ = 1; - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Forcibly exiting congestion due to " - << "timeout with " << tokens_[token_control].remaining - << " tokens.\n" << logofs_flush; - #endif - - congestion_ = 0; - } - } - else - { - #if defined(TEST) || defined(INFO) - - if (congestion_ == 0) - { - *logofs << "Proxy: Entering congestion due to timeout " - << "with " << tokens_[token_control].remaining - << " tokens.\n" << logofs_flush; - } - - #endif - - congestion_ = 1; - } - - if (control -> ProxyTimeout > 0 && - diffIn >= (control -> ProxyTimeout - - control -> LatencyTimeout)) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! No data received from " - << "remote proxy on FD#" << fd_ << " within " - << (diffIn + control -> LatencyTimeout) / 1000 - << " seconds.\n" << logofs_flush; - #endif - - cerr << "Error" << ": No data received from remote " - << "proxy within " << (diffIn + control -> - LatencyTimeout) / 1000 << " seconds.\n"; - - HandleAbort(); - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: WARNING! No data received from " - << "remote proxy on FD#" << fd_ << " since " - << diffIn << " Ms.\n" << logofs_flush; - #endif - - if (control -> ProxyTimeout > 0 && - isTimestamp(timeouts_.alertTs) == 0 && - diffIn >= (control -> ProxyTimeout - - control -> LatencyTimeout) / 4) - { - // - // If we are in the middle of a shutdown - // procedure but the remote is not resp- - // onding, force the closure of the link. - // - - if (finish_ != 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! No response received from " - << "the remote proxy on FD#" << fd_ << " while " - << "waiting for the shutdown.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": No response received from remote " - << "proxy while waiting for the shutdown.\n"; - - HandleAbort(); - } - else - { - cerr << "Warning" << ": No data received from remote " - << "proxy within " << (diffIn + control -> - LatencyTimeout) / 1000 << " seconds.\n"; - - if (alert_ == 0) - { - if (control -> ProxyMode == proxy_client) - { - alert_ = CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT; - } - else - { - alert_ = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT; - } - - HandleAlert(alert_, 1); - } - - timeouts_.alertTs = nowTs; - } - } - } - } - - // - // Check if we need to update the congestion - // counter. - // - - int diffOut = diffTimestamp(timeouts_.writeTs, nowTs); - - if (agent_ != nothing && congestions_[agent_] == 0 && - statistics -> getCongestionInFrame() >= 1 && - diffOut >= (control -> IdleTimeout - - control -> LatencyTimeout * 5)) - { - #if defined(TEST) || defined(INFO) || defined(PING) - *logofs << "Proxy: Forcing an update of the " - << "congestion counter after timeout.\n" - << logofs_flush; - #endif - - statistics -> updateCongestion(tokens_[token_control].remaining, - tokens_[token_control].limit); - } - - // - // Send a new token if we didn't send any data to - // the remote for longer than the ping timeout. - // The client side sends a token, the server side - // responds with a token reply. - // - // VMWare virtual machines can have the system - // timer deadly broken. Try to send a ping regard- - // less we are the client or the server proxy to - // force a write by the remote. - // - - if (control -> ProxyMode == proxy_client || - diffIn >= (control -> PingTimeout * 4) - - control -> LatencyTimeout) - { - // - // We need to send a new ping even if we didn't - // receive anything from the remote within the - // ping timeout. The server side will respond - // to our ping, so we use the ping to force the - // remote end to send some data. - // - - if (diffIn >= (control -> PingTimeout - - control -> LatencyTimeout * 5) || - diffOut >= (control -> PingTimeout - - control -> LatencyTimeout * 5)) - { - int diffPing = diffTimestamp(timeouts_.pingTs, nowTs); - - if (diffPing < 0 || diffPing >= (control -> PingTimeout - - control -> LatencyTimeout * 5)) - { - #if defined(TEST) || defined(INFO) || defined(PING) - *logofs << "Proxy: Sending a new ping at " << strMsTimestamp() - << " with " << tokens_[token_control].remaining - << " tokens and elapsed in " << diffIn << " out " - << diffOut << " ping " << diffPing - << ".\n" << logofs_flush; - #endif - - if (handleFrame(frame_ping) < 0) - { - return -1; - } - - timeouts_.pingTs = nowTs; - } - #if defined(TEST) || defined(INFO) || defined(PING) - else - { - *logofs << "Proxy: Not sending a new ping with " - << "elapsed in " << diffIn << " out " - << diffOut << " ping " << diffPing - << ".\n" << logofs_flush; - } - #endif - } - } - - return 1; -} - -int Proxy::handleSyncFromProxy(int channelId) -{ - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: WARNING! Received a synchronization " - << "request from the remote proxy.\n" - << logofs_flush; - #endif - - if (handleControl(code_sync_reply, channelId) < 0) - { - return -1; - } - - return 1; -} - -int Proxy::handleResetStores() -{ - // - // Recreate the message stores. - // - - delete clientStore_; - delete serverStore_; - - clientStore_ = new ClientStore(compressor_); - serverStore_ = new ServerStore(compressor_); - - timeouts_.loadTs = nullTimestamp(); - - // - // Replace message stores in channels. - // - - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] != NULL) - { - if (channels_[channelId] -> setStores(clientStore_, serverStore_) < 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Failed to replace message stores in " - << "channel for FD#" << getFd(channelId) << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed to replace message stores in " - << "channel for FD#" << getFd(channelId) << ".\n"; - - return -1; - } - #ifdef TEST - else - { - *logofs << "Proxy: Replaced message stores in channel " - << "for FD#" << getFd(channelId) << ".\n" - << logofs_flush; - } - #endif - } - } - - return 1; -} - -int Proxy::handleResetPersistentCache() -{ - char *fullName = new char[strlen(control -> PersistentCachePath) + - strlen(control -> PersistentCacheName) + 2]; - - strcpy(fullName, control -> PersistentCachePath); - strcat(fullName, "/"); - strcat(fullName, control -> PersistentCacheName); - - #ifdef TEST - *logofs << "Proxy: Going to remove persistent cache file '" - << fullName << "'\n" << logofs_flush; - #endif - - unlink(fullName); - - delete [] fullName; - - delete [] control -> PersistentCacheName; - - control -> PersistentCacheName = NULL; - - return 1; -} - -void Proxy::handleResetFlush() -{ - #ifdef TEST - *logofs << "Proxy: Going to reset flush counters " - << "for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - // - // Reset the proxy priority flag. - // - - priority_ = 0; - - // - // Restore buffers to their initial - // size. - // - - transport_ -> partialReset(); - - // - // Update the timestamp of the last - // write operation performed on the - // socket. - // - - timeouts_.writeTs = getTimestamp(); -} - -int Proxy::handleFinish() -{ - // - // Reset the timestamps to give the proxy - // another chance to show the 'no response' - // dialog if the shutdown message doesn't - // come in time. - // - - timeouts_.readTs = getTimestamp(); - - timeouts_.alertTs = nullTimestamp(); - - finish_ = 1; - - return 1; -} - -int Proxy::handleShutdown() -{ - // - // Send shutdown message to remote proxy. - // - - shutdown_ = 1; - - handleControl(code_shutdown_request); - - #ifdef TEST - *logofs << "Proxy: Starting shutdown procedure " - << "for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - // - // Ensure that all the data accumulated - // in the transport buffer is flushed - // to the network layer. - // - - for (int i = 0; i < 100; i++) - { - if (canFlush() == 1) - { - handleFlush(); - } - else - { - break; - } - - usleep(100000); - } - - // - // Now wait for the network layers to - // consume all the data. - // - - for (int i = 0; i < 100; i++) - { - if (transport_ -> queued() <= 0) - { - break; - } - - usleep(100000); - } - - // - // Give time to the remote end to read - // the shutdown message and close the - // connection. - // - - transport_ -> wait(10000); - - #ifdef TEST - *logofs << "Proxy: Ending shutdown procedure " - << "for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - return 1; -} - -int Proxy::handleChannelConfiguration() -{ - if (activeChannels_.getSize() == 0) - { - #ifdef TEST - *logofs << "Proxy: Going to initialize the static " - << "members in channels for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - Channel::setReferences(); - - ClientChannel::setReferences(); - ServerChannel::setReferences(); - - GenericChannel::setReferences(); - } - - return 1; -} - -int Proxy::handleSocketConfiguration() -{ - // - // Set linger mode on proxy to correctly - // get shutdown notification. - // - - SetLingerTimeout(fd_, 30); - - // - // Set keep-alive on socket so that if remote link - // terminates abnormally (as killed hard or because - // of a power-off) process will get a SIGPIPE. In - // practice this is useless as proxies already ping - // each other every few seconds. - // - - if (control -> OptionProxyKeepAlive == 1) - { - SetKeepAlive(fd_); - } - - // - // Set 'priority' flag at TCP layer for path - // proxy-to-proxy. Look at IPTOS_LOWDELAY in - // man 7 ip. - // - - if (control -> OptionProxyLowDelay == 1) - { - SetLowDelay(fd_); - } - - // - // Update size of TCP send and receive buffers. - // - - if (control -> OptionProxySendBuffer != -1) - { - SetSendBuffer(fd_, control -> OptionProxySendBuffer); - } - - if (control -> OptionProxyReceiveBuffer != -1) - { - SetReceiveBuffer(fd_, control -> OptionProxyReceiveBuffer); - } - - // - // Update TCP_NODELAY settings. Note that on old Linux - // kernels turning off the Nagle algorithm didn't work - // when proxy was run through a PPP link. Trying to do - // so caused the kernel to stop delivering data to us - // if a serious network congestion was encountered. - // - - if (control -> ProxyMode == proxy_client) - { - if (control -> OptionProxyClientNoDelay != -1) - { - SetNoDelay(fd_, control -> OptionProxyClientNoDelay); - } - } - else - { - if (control -> OptionProxyServerNoDelay != -1) - { - SetNoDelay(fd_, control -> OptionProxyServerNoDelay); - } - } - - return 1; -} - -int Proxy::handleLinkConfiguration() -{ - #ifdef TEST - *logofs << "Proxy: Propagating parameters to " - << "channels' read buffers.\n" - << logofs_flush; - #endif - - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] != NULL) - { - channels_[channelId] -> handleConfiguration(); - } - } - - #ifdef TEST - *logofs << "Proxy: Propagating parameters to " - << "proxy buffers.\n" - << logofs_flush; - #endif - - readBuffer_.setSize(control -> ProxyInitialReadSize, - control -> ProxyMaximumBufferSize); - - encodeBuffer_.setSize(control -> TransportProxyBufferSize, - control -> TransportProxyBufferThreshold, - control -> TransportMaximumBufferSize); - - transport_ -> setSize(control -> TransportProxyBufferSize, - control -> TransportProxyBufferThreshold, - control -> TransportMaximumBufferSize); - - #ifdef TEST - *logofs << "Proxy: Configuring the proxy timeouts.\n" - << logofs_flush; - #endif - - timeouts_.split = control -> SplitTimeout; - timeouts_.motion = control -> MotionTimeout; - - #ifdef TEST - *logofs << "Proxy: Configuring the proxy tokens.\n" - << logofs_flush; - #endif - - tokens_[token_control].size = control -> TokenSize; - tokens_[token_control].limit = control -> TokenLimit; - - if (tokens_[token_control].limit < 1) - { - tokens_[token_control].limit = 1; - } - - #if defined(TEST) || defined(INFO) || defined(LIMIT) - *logofs << "Proxy: TOKEN! LIMIT! Setting token [" - << DumpToken(token_control) << "] size to " - << tokens_[token_control].size << " and limit to " - << tokens_[token_control].limit << ".\n" - << logofs_flush; - #endif - - tokens_[token_split].size = control -> TokenSize; - tokens_[token_split].limit = control -> TokenLimit / 2; - - if (tokens_[token_split].limit < 1) - { - tokens_[token_split].limit = 1; - } - - #if defined(TEST) || defined(INFO) || defined(LIMIT) - *logofs << "Proxy: TOKEN! LIMIT! Setting token [" - << DumpToken(token_split) << "] size to " - << tokens_[token_split].size << " and limit to " - << tokens_[token_split].limit << ".\n" - << logofs_flush; - #endif - - tokens_[token_data].size = control -> TokenSize; - tokens_[token_data].limit = control -> TokenLimit / 4; - - if (tokens_[token_data].limit < 1) - { - tokens_[token_data].limit = 1; - } - - #if defined(TEST) || defined(INFO) || defined(LIMIT) - *logofs << "Proxy: TOKEN! LIMIT! Setting token [" - << DumpToken(token_data) << "] size to " - << tokens_[token_data].size << " and limit to " - << tokens_[token_data].limit << ".\n" - << logofs_flush; - #endif - - for (int i = token_control; i <= token_data; i++) - { - tokens_[i].remaining = tokens_[i].limit; - } - - #if defined(TEST) || defined(INFO) || defined(LIMIT) - *logofs << "Proxy: LIMIT! Using client bitrate " - << "limit " << control -> ClientBitrateLimit - << " server bitrate limit " << control -> - ServerBitrateLimit << " with local limit " - << control -> LocalBitrateLimit << ".\n" - << logofs_flush; - #endif - - // - // Set the other parameters based on - // the token size. - // - - int base = control -> TokenSize; - - control -> SplitDataThreshold = base * 4; - control -> SplitDataPacketLimit = base / 2; - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: LIMIT! Setting split data threshold " - << "to " << control -> SplitDataThreshold - << " split packet limit to " << control -> - SplitDataPacketLimit << " with base " - << base << ".\n" << logofs_flush; - #endif - - // - // Set the number of bytes read from the - // data channels at each loop. This will - // basically determine the maximum band- - // width available for the generic chan- - // nels. - // - - control -> GenericInitialReadSize = base / 2; - control -> GenericMaximumBufferSize = base / 2; - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: LIMIT! Setting generic channel " - << "initial read size to " << control -> - GenericInitialReadSize << " maximum read " - << "size to " << control -> GenericMaximumBufferSize - << " with base " << base << ".\n" - << logofs_flush; - #endif - - return 1; -} - -int Proxy::handleCacheConfiguration() -{ - #ifdef TEST - *logofs << "Proxy: Configuring cache according to pack parameters.\n" - << logofs_flush; - #endif - - // - // Further adjust the cache parameters. If - // packing of the images is enabled, reduce - // the size available for plain images. - // - - if (control -> SessionMode == session_agent) - { - if (control -> PackMethod != NO_PACK) - { - clientStore_ -> getRequestStore(X_PutImage) -> - cacheThreshold = PUTIMAGE_CACHE_THRESHOLD_IF_PACKED; - - clientStore_ -> getRequestStore(X_PutImage) -> - cacheLowerThreshold = PUTIMAGE_CACHE_LOWER_THRESHOLD_IF_PACKED; - } - } - - // - // If this is a shadow session increase the - // size of the image cache. - // - - if (control -> SessionMode == session_shadow) - { - if (control -> PackMethod != NO_PACK) - { - clientStore_ -> getRequestStore(X_NXPutPackedImage) -> - cacheThreshold = PUTPACKEDIMAGE_CACHE_THRESHOLD_IF_PACKED_SHADOW; - - clientStore_ -> getRequestStore(X_NXPutPackedImage) -> - cacheLowerThreshold = PUTPACKEDIMAGE_CACHE_LOWER_THRESHOLD_IF_PACKED_SHADOW; - } - else - { - clientStore_ -> getRequestStore(X_PutImage) -> - cacheThreshold = PUTIMAGE_CACHE_THRESHOLD_IF_SHADOW; - - clientStore_ -> getRequestStore(X_PutImage) -> - cacheLowerThreshold = PUTIMAGE_CACHE_LOWER_THRESHOLD_IF_SHADOW; - } - } - - return 1; -} - -int Proxy::handleSaveStores() -{ - // - // Save content of stores on disk. - // - - char *cacheToAdopt = NULL; - - // - // Set to false the indicator for cumulative store - // size too small - // - bool isTooSmall = false; - - if (control -> PersistentCacheEnableSave) - { - #ifdef TEST - *logofs << "Proxy: Going to save content of client store.\n" - << logofs_flush; - #endif - - cacheToAdopt = handleSaveAllStores(control -> PersistentCachePath, isTooSmall); - } - #ifdef TEST - else - { - if (control -> ProxyMode == proxy_client) - { - *logofs << "Proxy: Saving persistent cache to disk disabled.\n" - << logofs_flush; - } - else - { - *logofs << "Proxy: PANIC! Protocol violation in command save.\n" - << logofs_flush; - - cerr << "Error" << ": Protocol violation in command save.\n"; - - HandleCleanup(); - } - } - #endif - - if (cacheToAdopt != NULL) - { - // - // Do we have a cache already? - // - - if (control -> PersistentCacheName != NULL) - { - // - // Check if old and new cache are the same. - // In this case don't remove the old cache. - // - - if (strcasecmp(control -> PersistentCacheName, cacheToAdopt) != 0) - { - handleResetPersistentCache(); - } - - delete [] control -> PersistentCacheName; - } - - #ifdef TEST - *logofs << "Proxy: Setting current persistent cache file to '" - << cacheToAdopt << "'\n" << logofs_flush; - #endif - - control -> PersistentCacheName = cacheToAdopt; - - return 1; - } - else - { - #ifdef TEST - *logofs << "Proxy: No cache file produced from message stores.\n" - << logofs_flush; - #endif - - // - // It can be that we didn't generate a new cache - // because store was too small or persistent cache - // was disabled. This is not an error. - // - - if (control -> PersistentCacheEnableSave && !isTooSmall) - { - return -1; - } - else - { - return 0; - } - } -} - -int Proxy::handleLoadStores() -{ - // - // Restore the content of the client store - // from disk if a valid cache was negotiated - // at session startup. - // - - if (control -> PersistentCacheEnableLoad == 1 && - control -> PersistentCachePath != NULL && - control -> PersistentCacheName != NULL) - { - #ifdef TEST - *logofs << "Proxy: Going to load content of client store.\n" - << logofs_flush; - #endif - - // - // Returns the same string passed as name of - // the cache, or NULL if it was not possible - // to load the cache from disk. - // - - if (handleLoadAllStores(control -> PersistentCachePath, - control -> PersistentCacheName) == NULL) - { - // - // The corrupted cache should have been - // removed from disk. Get rid of the - // reference so we don't try to delete - // it once again. - // - - if (control -> PersistentCacheName != NULL) - { - delete [] control -> PersistentCacheName; - } - - control -> PersistentCacheName = NULL; - - return -1; - } - - // - // Set timestamp of last time cache - // was loaded from data on disk. - // - - timeouts_.loadTs = getTimestamp(); - - return 1; - } - #ifdef TEST - else - { - if (control -> ProxyMode == proxy_client) - { - *logofs << "Proxy: Loading of cache disabled or no cache file selected.\n" - << logofs_flush; - } - else - { - *logofs << "Proxy: PANIC! Protocol violation in command load.\n" - << logofs_flush; - - cerr << "Error" << ": Protocol violation in command load.\n"; - - HandleCleanup(); - } - } - #endif - - return 0; -} - -int Proxy::handleControl(T_proxy_code code, int data) -{ - // - // Send the given control messages - // to the remote proxy. - // - - #if defined(TEST) || defined(INFO) - - if (data != -1) - { - if (code == code_control_token_reply || - code == code_split_token_reply || - code == code_data_token_reply) - { - *logofs << "Proxy: TOKEN! Sending message '" << DumpControl(code) - << "' at " << strMsTimestamp() << " with count " - << data << ".\n" << logofs_flush; - } - else - { - *logofs << "Proxy: Sending message '" << DumpControl(code) - << "' at " << strMsTimestamp() << " with data ID#" - << data << ".\n" << logofs_flush; - } - } - else - { - *logofs << "Proxy: Sending message '" << DumpControl(code) - << "' at " << strMsTimestamp() << ".\n" - << logofs_flush; - } - - #endif - - // - // Add the control message and see if the - // data has to be flushed immediately. - // - - if (addControlCodes(code, data) < 0) - { - return -1; - } - - switch (code) - { - // - // Append the first data read from the opened - // channel to the control code. - // - - case code_new_x_connection: - case code_new_cups_connection: - case code_new_aux_connection: - case code_new_smb_connection: - case code_new_media_connection: - case code_new_http_connection: - case code_new_font_connection: - case code_new_slave_connection: - - // - // Do we send the token reply immediately? - // The control messages are put at the begin- - // ning of the of the encode buffer, so we may - // reply to multiple tokens before having the - // chance of handling the actual frame data. - // On the other hand, the sooner we reply, the - // sooner the remote proxy is restarted. - // - - case code_control_token_reply: - case code_split_token_reply: - case code_data_token_reply: - { - break; - } - - // - // Also send the congestion control codes - // immediately. - // - // case code_begin_congestion: - // case code_end_congestion: - // - - default: - { - priority_ = 1; - - break; - } - } - - if (priority_ == 1) - { - if (handleFrame(frame_data) < 0) - { - return -1; - } - } - - return 1; -} - -int Proxy::handleSwitch(int channelId) -{ - // - // If data is for a different channel than last - // selected for output, prepend to the data the - // new channel id. - // - - #ifdef DEBUG - *logofs << "Proxy: Requested a switch with " - << "current channel ID#" << outputChannel_ - << " new channel ID#" << channelId << ".\n" - << logofs_flush; - #endif - - if (channelId != outputChannel_) - { - if (needFlush() == 1) - { - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "Proxy: WARNING! Flushing data for the " - << "previous channel ID#" << outputChannel_ - << ".\n" << logofs_flush; - #endif - - if (handleFrame(frame_data) < 0) - { - return -1; - } - } - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Sending message '" - << DumpControl(code_switch_connection) << "' at " - << strMsTimestamp() << " with FD#" << getFd(channelId) - << " channel ID#" << channelId << ".\n" - << logofs_flush; - #endif - - if (addControlCodes(code_switch_connection, channelId) < 0) - { - return -1; - } - - outputChannel_ = channelId; - } - - return 1; -} - -int Proxy::addTokenCodes(T_proxy_token &token) -{ - #if defined(TEST) || defined(INFO) || defined(TOKEN) - *logofs << "Proxy: TOKEN! Sending token [" - << DumpToken(token.type) << "] with " - << token.bytes << " bytes accumulated size " - << token.size << " and " << token.remaining - << " available.\n" << logofs_flush; - #endif - - // - // Give a 'weight' to the token. The tokens - // remaining can become negative if we sent - // a packet that was exceptionally big. - // - - int count = 0; - - // Since ProtoStep7 (#issue 108) - count = token.bytes / token.size; - - // - // Force a count of 1, for example - // if this is a ping. - // - - if (count < 1) - { - count = 1; - - token.bytes = 0; - } - else - { - // Since ProtoStep7 (#issue 108) - if (count > 255) - { - count = 255; - } - - // - // Let the next token account for the - // remaining bytes. - // - - token.bytes %= token.size; - } - - #if defined(TEST) || defined(INFO) || defined(TOKEN) - *logofs << "Proxy: Sending message '" - << DumpControl(token.request) << "' at " - << strMsTimestamp() << " with count " << count - << ".\n" << logofs_flush; - #endif - - controlCodes_[controlLength_++] = 0; - controlCodes_[controlLength_++] = (unsigned char) token.request; - controlCodes_[controlLength_++] = (unsigned char) count; - - statistics -> addFrameOut(); - - token.remaining -= count; - - return 1; -} - -int Proxy::handleToken(T_frame_type type) -{ - #if defined(TEST) || defined(INFO) || defined(TOKEN) - *logofs << "Proxy: TOKEN! Checking tokens with " - << "frame type ["; - - *logofs << (type == frame_ping ? "frame_ping" : "frame_data"); - - *logofs << "] with stream ratio " << statistics -> - getStreamRatio() << ".\n" << logofs_flush; - #endif - - if (type == frame_data) - { - // - // Since ProtoStep7 (#issue 108) - // - - // Send a distinct token for each data type. - // We don't want to slow down the sending of - // the X events, X replies and split confir- - // mation events on the X server side, so - // take care only of the generic data token. - // - - if (control -> ProxyMode == proxy_client) - { - statistics -> updateControlToken(tokens_[token_control].bytes); - - if (tokens_[token_control].bytes > tokens_[token_control].size) - { - if (addTokenCodes(tokens_[token_control]) < 0) - { - return -1; - } - - #if defined(TEST) || defined(INFO) || defined(TOKEN) - - T_proxy_token &token = tokens_[token_control]; - - *logofs << "Proxy: TOKEN! Token class [" - << DumpToken(token.type) << "] has now " - << token.bytes << " bytes accumulated and " - << token.remaining << " tokens remaining.\n" - << logofs_flush; - #endif - } - - statistics -> updateSplitToken(tokens_[token_split].bytes); - - if (tokens_[token_split].bytes > tokens_[token_split].size) - { - if (addTokenCodes(tokens_[token_split]) < 0) - { - return -1; - } - - #if defined(TEST) || defined(INFO) || defined(TOKEN) - - T_proxy_token &token = tokens_[token_split]; - - *logofs << "Proxy: TOKEN! Token class [" - << DumpToken(token.type) << "] has now " - << token.bytes << " bytes accumulated and " - << token.remaining << " tokens remaining.\n" - << logofs_flush; - #endif - } - } - - statistics -> updateDataToken(tokens_[token_data].bytes); - - if (tokens_[token_data].bytes > tokens_[token_data].size) - { - if (addTokenCodes(tokens_[token_data]) < 0) - { - return -1; - } - - #if defined(TEST) || defined(INFO) || defined(TOKEN) - - T_proxy_token &token = tokens_[token_data]; - - *logofs << "Proxy: TOKEN! Token class [" - << DumpToken(token.type) << "] has now " - << token.bytes << " bytes accumulated and " - << token.remaining << " tokens remaining.\n" - << logofs_flush; - #endif - } - } - else - { - if (addTokenCodes(tokens_[token_control]) < 0) - { - return -1; - } - - // - // Reset all counters on a ping. - // - - tokens_[token_control].bytes = 0; - tokens_[token_split].bytes = 0; - tokens_[token_data].bytes = 0; - - #if defined(TEST) || defined(INFO) || defined(TOKEN) - - T_proxy_token &token = tokens_[token_control]; - - *logofs << "Proxy: TOKEN! Token class [" - << DumpToken(token.type) << "] has now " - << token.bytes << " bytes accumulated and " - << token.remaining << " tokens remaining.\n" - << logofs_flush; - #endif - } - - // - // Check if we have entered in - // congestion state. - // - - if (congestion_ == 0 && - tokens_[token_control].remaining <= 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Entering congestion with " - << tokens_[token_control].remaining - << " tokens remaining.\n" << logofs_flush; - #endif - - congestion_ = 1; - } - - statistics -> updateCongestion(tokens_[token_control].remaining, - tokens_[token_control].limit); - - return 1; -} - -int Proxy::handleTokenFromProxy(T_proxy_token &token, int count) -{ - #if defined(TEST) || defined(INFO) || defined(TOKEN) - *logofs << "Proxy: TOKEN! Received token [" - << DumpToken(token.type) << "] request at " - << strMsTimestamp() << " with count " - << count << ".\n" << logofs_flush; - #endif - - // - // Since ProtoStep7 (#issue 108) with no limitations - // concerning invalid token requests at this point - // - - // - // Add our token reply. - // - - if (handleControl(token.reply, count) < 0) - { - return -1; - } - - return 1; -} - -int Proxy::handleTokenReplyFromProxy(T_proxy_token &token, int count) -{ - #if defined(TEST) || defined(INFO) || defined(TOKEN) - *logofs << "Proxy: TOKEN! Received token [" - << DumpToken(token.type) << "] reply at " - << strMsTimestamp() << " with count " << count - << ".\n" << logofs_flush; - #endif - - // - // Since ProtoStep7 (#issue 108) with no limitations - // concerning invalid token requests at this point - // - - // - // Increment the available tokens. - // - - token.remaining += count; - - if (token.remaining > token.limit) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Token overflow handling messages.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Token overflow handling messages.\n"; - - HandleCleanup(); - } - - #if defined(TEST) || defined(INFO) || defined(TOKEN) - *logofs << "Proxy: TOKEN! Token class [" - << DumpToken(token.type) << "] has now " << token.bytes - << " bytes accumulated and " << token.remaining - << " tokens remaining.\n" << logofs_flush; - #endif - - // - // Check if we can jump out of the - // congestion state. - // - - if (congestion_ == 1 && - tokens_[token_control].remaining > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Exiting congestion with " - << tokens_[token_control].remaining - << " tokens remaining.\n" << logofs_flush; - #endif - - congestion_ = 0; - } - - statistics -> updateCongestion(tokens_[token_control].remaining, - tokens_[token_control].limit); - - return 1; -} - -void Proxy::handleFailOnSave(const char *fullName, const char *failContext) const -{ - #ifdef WARNING - *logofs << "Proxy: WARNING! Error saving stores to cache file " - << "in context [" << failContext << "].\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Error saving stores to cache file " - << "in context [" << failContext << "].\n"; - - #ifdef WARNING - *logofs << "Proxy: WARNING! Removing invalid cache '" - << fullName << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Removing invalid cache '" - << fullName << "'.\n"; - - unlink(fullName); -} - -void Proxy::handleFailOnLoad(const char *fullName, const char *failContext) const -{ - #ifdef WARNING - *logofs << "Proxy: WARNING! Error loading stores from cache file " - << "in context [" << failContext << "].\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Error loading stores from cache file " - << "in context [" << failContext << "].\n"; - - #ifdef WARNING - *logofs << "Proxy: WARNING! Removing invalid cache '" - << fullName << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Removing invalid cache '" - << fullName << "'.\n"; - - unlink(fullName); -} - -int Proxy::handleSaveVersion(unsigned char *buffer, int &major, - int &minor, int &patch) const -{ - // Since ProtoStep8 (#issue 108) - major = 3; - minor = 0; - patch = 0; - - *(buffer + 0) = major; - *(buffer + 1) = minor; - - PutUINT(patch, buffer + 2, storeBigEndian()); - - return 1; -} - -int Proxy::handleLoadVersion(const unsigned char *buffer, int &major, - int &minor, int &patch) const -{ - major = *(buffer + 0); - minor = *(buffer + 1); - - patch = GetUINT(buffer + 2, storeBigEndian()); - - // - // Force the proxy to discard the - // incompatible caches. - // - - // Since ProtoStep8 (#issue 108) - if (major < 3) - { - return -1; - } - - return 1; -} - -char *Proxy::handleSaveAllStores(const char *savePath, bool & isTooSmall) const -{ - isTooSmall = false; - - int cumulativeSize = MessageStore::getCumulativeTotalStorageSize(); - - if (cumulativeSize < control -> PersistentCacheThreshold) - { - #ifdef TEST - *logofs << "Proxy: Cache not saved as size is " - << cumulativeSize << " with threshold set to " - << control -> PersistentCacheThreshold - << ".\n" << logofs_flush; - #endif - - // - // Cumulative store size is smaller than threshold - // so the indicator is set to true - // - - isTooSmall = true; - - return NULL; - } - else if (savePath == NULL) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! No name provided for save path.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": No name provided for save path.\n"; - - return NULL; - } - - #ifdef TEST - *logofs << "Proxy: Going to save content of message stores.\n" - << logofs_flush; - #endif - - // - // Our parent process is likely going to terminate. - // Until we finish saving cache we must ignore its - // SIGIPE. - // - - DisableSignals(); - - ofstream *cachefs = NULL; - - md5_state_t *md5StateStream = NULL; - md5_byte_t *md5DigestStream = NULL; - - md5_state_t *md5StateClient = NULL; - md5_byte_t *md5DigestClient = NULL; - - char md5String[MD5_LENGTH * 2 + 2]; - - char fullName[strlen(savePath) + MD5_LENGTH * 2 + 4]; - - // - // Prepare the template for the temporary file - // - - const char* const uniqueTemplate = "XXXXXX"; - char tempName[strlen(savePath) + strlen("/") + 4 + strlen(uniqueTemplate) + 1]; - - snprintf(tempName, sizeof tempName, "%s/%s%s", - savePath, - control -> ProxyMode == proxy_client ? - "Z-C-" : - "Z-S-", - uniqueTemplate); - - #ifdef TEST - *logofs << "Proxy: Generating temporary file with template '" - << tempName << "'.\n" << logofs_flush; - #endif - - // - // Change the mask to make the file only - // readable by the user, then restore the - // old mask. - // - - mode_t fileMode = umask(0077); - - // - // Generate a unique temporary filename from tempName - // and then create and open the file - // - - int fdTemp = mkstemp(tempName); - if (fdTemp == -1) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Can't create temporary file in '" - << savePath << "'. Cause = " << strerror(errno) << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't create temporary file in '" - << savePath << "'. Cause = " << strerror(errno) << ".\n"; - - umask(fileMode); - - EnableSignals(); - - return NULL; - } - - #ifdef TEST - *logofs << "Proxy: Saving cache to file '" - << tempName << "'.\n" << logofs_flush; - #endif - - // - // Create and open the output stream for the new temporary - // file - // - - cachefs = new (std::nothrow) ofstream(tempName, ios::out | ios::binary); - if ((cachefs == NULL) || cachefs->fail()) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Can't create stream for temporary file '" - << tempName << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't create stream for temporary file '" - << tempName << "'.\n"; - - close(fdTemp); - unlink(tempName); - - umask(fileMode); - - EnableSignals(); - - return NULL; - } - - // - // Close the file descriptor returned by mkstemp - // and restore the old mask - // - - close(fdTemp); - umask(fileMode); - - md5StateStream = new md5_state_t(); - md5DigestStream = new md5_byte_t[MD5_LENGTH]; - - md5_init(md5StateStream); - - // - // First write the proxy version. - // - - unsigned char version[4]; - - int major; - int minor; - int patch; - - handleSaveVersion(version, major, minor, patch); - - #ifdef TEST - *logofs << "Proxy: Saving cache using version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - - if (PutData(cachefs, version, 4) < 0) - { - handleFailOnSave(tempName, "A"); - - delete cachefs; - - delete md5StateStream; - delete [] md5DigestStream; - - EnableSignals(); - - return NULL; - } - - // - // Make space for the calculated MD5 so we - // can later rewind the file and write it - // at this position. - // - - if (PutData(cachefs, md5DigestStream, MD5_LENGTH) < 0) - { - handleFailOnSave(tempName, "B"); - - delete cachefs; - - delete md5StateStream; - delete [] md5DigestStream; - - EnableSignals(); - - return NULL; - } - - md5StateClient = new md5_state_t(); - md5DigestClient = new md5_byte_t[MD5_LENGTH]; - - md5_init(md5StateClient); - - #ifdef DUMP - - ofstream *cacheDump = NULL; - - ofstream *tempfs = (ofstream*) logofs; - - char cacheDumpName[DEFAULT_STRING_LENGTH]; - - if (control -> ProxyMode == proxy_client) - { - snprintf(cacheDumpName, DEFAULT_STRING_LENGTH - 1, - "%s/client-cache-dump", control -> TempPath); - } - else - { - snprintf(cacheDumpName, DEFAULT_STRING_LENGTH - 1, - "%s/server-cache-dump", control -> TempPath); - } - - *(cacheDumpName + DEFAULT_STRING_LENGTH - 1) = '\0'; - - fileMode = umask(0077); - - cacheDump = new ofstream(cacheDumpName, ios::out); - - umask(fileMode); - - logofs = cacheDump; - - #endif - - // - // Use the virtual method of the concrete proxy class. - // - - int allSaved = handleSaveAllStores(cachefs, md5StateStream, md5StateClient); - - #ifdef DUMP - - logofs = tempfs; - - delete cacheDump; - - #endif - - if (allSaved == -1) - { - handleFailOnSave(tempName, "C"); - - delete cachefs; - - delete md5StateStream; - delete [] md5DigestStream; - - delete md5StateClient; - delete [] md5DigestClient; - - EnableSignals(); - - return NULL; - } - - md5_finish(md5StateClient, md5DigestClient); - - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - sprintf(md5String + (i * 2), "%02X", md5DigestClient[i]); - } - - strcpy(fullName, (control -> ProxyMode == proxy_client) ? "C-" : "S-"); - - strcat(fullName, md5String); - - md5_append(md5StateStream, (const md5_byte_t *) fullName, strlen(fullName)); - md5_finish(md5StateStream, md5DigestStream); - - // - // Go to the beginning of file plus - // the integer where we wrote our - // proxy version. - // - - cachefs -> seekp(4); - - if (PutData(cachefs, md5DigestStream, MD5_LENGTH) < 0) - { - handleFailOnSave(tempName, "D"); - - delete cachefs; - - delete md5StateStream; - delete [] md5DigestStream; - - delete md5StateClient; - delete [] md5DigestClient; - - EnableSignals(); - - return NULL; - } - - delete cachefs; - - // - // Copy the resulting cache name without - // the path so that we can return it to - // the caller. - // - - char *cacheName = new char[MD5_LENGTH * 2 + 4]; - - strcpy(cacheName, fullName); - - // - // Add the path to the full name and move - // the cache into the path. - // - - strcpy(fullName, savePath); - strcat(fullName, (control -> ProxyMode == proxy_client) ? "/C-" : "/S-"); - strcat(fullName, md5String); - - #ifdef TEST - *logofs << "Proxy: Renaming cache file from '" - << tempName << "' to '" << fullName - << "'.\n" << logofs_flush; - #endif - - rename(tempName, fullName); - - delete md5StateStream; - delete [] md5DigestStream; - - delete md5StateClient; - delete [] md5DigestClient; - - // - // Restore the original handlers. - // - - EnableSignals(); - - #ifdef TEST - *logofs << "Proxy: Successfully saved cache file '" - << cacheName << "'.\n" << logofs_flush; - #endif - - // - // This must be enabled only for test - // because it requires that client and - // server reside on the same machine. - // - - if (control -> PersistentCacheCheckOnShutdown == 1 && - control -> ProxyMode == proxy_server) - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: MATCH! Checking if the file '" - << fullName << "' matches a client cache.\n" - << logofs_flush; - #endif - - strcpy(fullName, savePath); - strcat(fullName, "/C-"); - strcat(fullName, md5String); - - struct stat fileStat; - - if (stat(fullName, &fileStat) != 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Can't find a client cache " - << "with name '" << fullName << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't find a client cache " - << "with name '" << fullName << "'.\n"; - - HandleShutdown(); - } - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: MATCH! Client cache '" << fullName - << "' matches the local cache.\n" - << logofs_flush; - #endif - } - - return cacheName; -} - -const char *Proxy::handleLoadAllStores(const char *loadPath, const char *loadName) const -{ - #ifdef TEST - *logofs << "Proxy: Going to load content of message stores.\n" - << logofs_flush; - #endif - - // - // Until we finish loading cache we - // must at least ignore any SIGIPE. - // - - DisableSignals(); - - if (loadPath == NULL || loadName == NULL) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! No path or no file name provided for cache to restore.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": No path or no file name provided for cache to restore.\n"; - - EnableSignals(); - - return NULL; - } - else if (strlen(loadName) != MD5_LENGTH * 2 + 2) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Bad file name provided for cache to restore.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Bad file name provided for cache to restore.\n"; - - EnableSignals(); - - return NULL; - } - - istream *cachefs = NULL; - char md5String[(MD5_LENGTH * 2) + 2]; - md5_byte_t md5FromFile[MD5_LENGTH]; - - char *cacheName = new char[strlen(loadPath) + strlen(loadName) + 3]; - - strcpy(cacheName, loadPath); - strcat(cacheName, "/"); - strcat(cacheName, loadName); - - #ifdef TEST - *logofs << "Proxy: Name of cache file is '" - << cacheName << "'.\n" << logofs_flush; - #endif - - cachefs = new ifstream(cacheName, ios::in | ios::binary); - - unsigned char version[4]; - - if (cachefs == NULL || GetData(cachefs, version, 4) < 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Can't read cache file '" - << cacheName << "'.\n" << logofs_flush;; - #endif - - handleFailOnLoad(cacheName, "A"); - - delete cachefs; - - delete [] cacheName; - - EnableSignals(); - - return NULL; - } - - int major; - int minor; - int patch; - - if (handleLoadVersion(version, major, minor, patch) < 0) - { - #ifdef PANIC - *logofs << "Proxy: WARNING! Incompatible version '" - << major << "." << minor << "." << patch - << "' in cache file '" << cacheName - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Incompatible version '" - << major << "." << minor << "." << patch - << "' in cache file '" << cacheName - << "'.\n" << logofs_flush; - - if (control -> ProxyMode == proxy_server) - { - handleFailOnLoad(cacheName, "B"); - } - else - { - // - // Simply remove the cache file. - // - - unlink(cacheName); - } - - delete cachefs; - - delete [] cacheName; - - EnableSignals(); - - return NULL; - } - - #ifdef TEST - *logofs << "Proxy: Reading from cache file version '" - << major << "." << minor << "." << patch - << "'.\n" << logofs_flush; - #endif - - if (GetData(cachefs, md5FromFile, MD5_LENGTH) < 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! No checksum in cache file '" - << loadName << "'.\n" << logofs_flush; - #endif - - handleFailOnLoad(cacheName, "C"); - - delete cachefs; - - delete [] cacheName; - - EnableSignals(); - - return NULL; - } - - md5_state_t *md5StateStream = NULL; - md5_byte_t *md5DigestStream = NULL; - - md5StateStream = new md5_state_t(); - md5DigestStream = new md5_byte_t[MD5_LENGTH]; - - md5_init(md5StateStream); - - // - // Use the virtual method of the proxy class. - // - - if (handleLoadAllStores(cachefs, md5StateStream) < 0) - { - handleFailOnLoad(cacheName, "D"); - - delete cachefs; - - delete md5StateStream; - delete [] md5DigestStream; - - delete [] cacheName; - - EnableSignals(); - - return NULL; - } - - md5_append(md5StateStream, (const md5_byte_t *) loadName, strlen(loadName)); - md5_finish(md5StateStream, md5DigestStream); - - for (int i = 0; i < MD5_LENGTH; i++) - { - if (md5DigestStream[i] != md5FromFile[i]) - { - #ifdef PANIC - - *logofs << "Proxy: PANIC! Bad checksum for cache file '" - << cacheName << "'.\n" << logofs_flush; - - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - sprintf(md5String + (i * 2), "%02X", md5FromFile[i]); - } - - *logofs << "Proxy: PANIC! Saved checksum is '" - << md5String << "'.\n" << logofs_flush; - - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - sprintf(md5String + (i * 2),"%02X", md5DigestStream[i]); - } - - *logofs << "Proxy: PANIC! Calculated checksum is '" - << md5String << "'.\n" << logofs_flush; - - #endif - - handleFailOnLoad(cacheName, "E"); - - delete cachefs; - - delete md5StateStream; - delete [] md5DigestStream; - - delete [] cacheName; - - EnableSignals(); - - return NULL; - } - } - - delete cachefs; - - delete md5StateStream; - delete [] md5DigestStream; - - delete [] cacheName; - - // - // Restore the original handlers. - // - - EnableSignals(); - - #ifdef TEST - *logofs << "Proxy: Successfully loaded cache file '" - << loadName << "'.\n" << logofs_flush; - #endif - - // - // Return the string provided by caller. - // - - return loadName; -} - -int Proxy::allocateChannelMap(int fd) -{ - // - // We assume that the fd is lower than - // the maximum allowed number. This is - // checked at the time the connection - // is accepted. - // - - if (fd < 0 || fd >= CONNECTIONS_LIMIT) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Internal error allocating " - << "new channel with FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Internal error allocating " - << "new channel with FD#" << fd_ << ".\n"; - - HandleCleanup(); - } - - for (int channelId = 0; - channelId < CONNECTIONS_LIMIT; - channelId++) - { - if (checkLocalChannelMap(channelId) == 1 && - fdMap_[channelId] == -1) - { - fdMap_[channelId] = fd; - channelMap_[fd] = channelId; - - #ifdef TEST - *logofs << "Proxy: Allocated new channel ID#" - << channelId << " with FD#" << fd << ".\n" - << logofs_flush; - #endif - - return channelId; - } - } - - // - // No available channel is remaining. - // - - #ifdef TEST - *logofs << "Proxy: WARNING! Can't allocate a new channel " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - return -1; -} - -int Proxy::checkChannelMap(int channelId) -{ - // - // To be acceptable, the channel id must - // be an id that is not possible to use - // to allocate channels at this side. - // - - if (checkLocalChannelMap(channelId) == 1) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Can't open a new channel " - << "with invalid ID#" << channelId << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't open a new channel " - << "with invalid ID#" << channelId << ".\n"; - - return -1; - } - else if (channels_[channelId] != NULL) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Can't open a new channel " - << "over an existing ID#" << channelId - << " with FD#" << getFd(channelId) - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't open a new channel " - << "over an existing ID#" << channelId - << " with FD#" << getFd(channelId) - << ".\n"; - - return -1; - } - - return 1; -} - -int Proxy::assignChannelMap(int channelId, int fd) -{ - // - // We assume that the fd is lower than - // the maximum allowed number. This is - // checked at the time the connection - // is accepted. - // - - if (channelId < 0 || channelId >= CONNECTIONS_LIMIT || - fd < 0 || fd >= CONNECTIONS_LIMIT) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Internal error assigning " - << "new channel with FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Internal error assigning " - << "new channel with FD#" << fd_ << ".\n"; - - HandleCleanup(); - } - - fdMap_[channelId] = fd; - channelMap_[fd] = channelId; - - return 1; -} - -void Proxy::cleanupChannelMap(int channelId) -{ - int fd = fdMap_[channelId]; - - if (fd != -1) - { - fdMap_[channelId] = -1; - channelMap_[fd] = -1; - } -} - -int Proxy::addControlCodes(T_proxy_code code, int data) -{ - // - // Flush the encode buffer plus all the outstanding - // control codes if there is not enough space for - // the new control message. We need to ensure that - // there are further bytes available, in the case - // we will need to add more token control messages. - // - - if (controlLength_ + 3 > CONTROL_CODES_THRESHOLD) - { - #ifdef WARNING - *logofs << "Proxy: WARNING! Flushing control messages " - << "while sending code '" << DumpControl(code) - << "'.\n" << logofs_flush; - #endif - - if (handleFlush() < 0) - { - return -1; - } - } - - controlCodes_[controlLength_++] = 0; - controlCodes_[controlLength_++] = (unsigned char) code; - controlCodes_[controlLength_++] = (unsigned char) (data == -1 ? 0 : data); - - // - // Account for the control frame. - // - - statistics -> addFrameOut(); - - return 1; -} - -void Proxy::setSplitTimeout(int channelId) -{ - int needed = channels_[channelId] -> needSplit(); - - if (needed != isTimestamp(timeouts_.splitTs)) - { - if (needed == 1) - { - #if defined(TEST) || defined(INFO) || defined(SPLIT) - *logofs << "Proxy: SPLIT! Allocating split timestamp at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - timeouts_.splitTs = getTimestamp(); - } - else - { - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] != NULL && - channels_[channelId] -> needSplit() == 1) - { - #ifdef TEST - *logofs << "Proxy: SPLIT! Channel for FD#" - << getFd(channelId) << " still needs splits.\n" - << logofs_flush; - #endif - - return; - } - } - - #if defined(TEST) || defined(INFO) || defined(SPLIT) - *logofs << "Proxy: SPLIT! Resetting split timestamp at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - timeouts_.splitTs = nullTimestamp(); - } - } -} - -void Proxy::setMotionTimeout(int channelId) -{ - int needed = channels_[channelId] -> needMotion(); - - if (needed != isTimestamp(timeouts_.motionTs)) - { - if (channels_[channelId] -> needMotion() == 1) - { - #if defined(TEST) || defined(INFO) || defined(SPLIT) - *logofs << "Proxy: Allocating motion timestamp at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - timeouts_.motionTs = getTimestamp(); - } - else - { - T_list &channelList = activeChannels_.getList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] != NULL && - channels_[channelId] -> needMotion() == 1) - { - #ifdef TEST - *logofs << "Proxy: SPLIT! Channel for FD#" - << getFd(channelId) << " still needs motions.\n" - << logofs_flush; - #endif - - return; - } - } - - #if defined(TEST) || defined(INFO) || defined(SPLIT) - *logofs << "Proxy: Resetting motion timestamp at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - timeouts_.motionTs = nullTimestamp(); - } - } -} - -void Proxy::increaseChannels(int channelId) -{ - #ifdef TEST - *logofs << "Proxy: Adding channel " << channelId - << " to the list of active channels.\n" - << logofs_flush; - #endif - - activeChannels_.add(channelId); - - #ifdef TEST - *logofs << "Proxy: There are " << activeChannels_.getSize() - << " allocated channels for proxy FD#" << fd_ - << ".\n" << logofs_flush; - #endif -} - -void Proxy::decreaseChannels(int channelId) -{ - #ifdef TEST - *logofs << "Proxy: Removing channel " << channelId - << " from the list of active channels.\n" - << logofs_flush; - #endif - - activeChannels_.remove(channelId); - - #ifdef TEST - *logofs << "Proxy: There are " << activeChannels_.getSize() - << " allocated channels for proxy FD#" << fd_ - << ".\n" << logofs_flush; - #endif -} - -int Proxy::allocateTransport(int channelFd, int channelId) -{ - if (transports_[channelId] == NULL) - { - transports_[channelId] = new Transport(channelFd); - - if (transports_[channelId] == NULL) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Can't allocate transport for " - << "channel id " << channelId << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate transport for " - << "channel id " << channelId << ".\n"; - - return -1; - } - } - else if (transports_[channelId] -> - getType() != transport_agent) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Transport for channel id " - << channelId << " should be null.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Transport for channel id " - << channelId << " should be null.\n"; - - return -1; - } - - return 1; -} - -int Proxy::deallocateTransport(int channelId) -{ - // - // Transport for the agent connection - // is passed from the outside when - // creating the channel. - // - - if (transports_[channelId] -> - getType() != transport_agent) - { - delete transports_[channelId]; - } - - transports_[channelId] = NULL; - - return 1; -} - -int Proxy::handleNewGenericConnection(int clientFd, T_channel_type type, const char *label) -{ - int channelId = allocateChannelMap(clientFd); - - if (channelId == -1) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Maximum number of available " - << "channels exceeded.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Maximum number of available " - << "channels exceeded.\n"; - - return -1; - } - - #ifdef TEST - *logofs << "Proxy: Channel for " << label << " descriptor " - << "FD#" << clientFd << " mapped to ID#" - << channelId << ".\n" - << logofs_flush; - #endif - - // - // Turn queuing off for path server-to-proxy. - // - - SetNoDelay(clientFd, 1); - - if (allocateTransport(clientFd, channelId) < 0) - { - return -1; - } - - switch (type) - { - case channel_cups: - { - channels_[channelId] = new CupsChannel(transports_[channelId], compressor_); - - break; - } - case channel_smb: - { - channels_[channelId] = new SmbChannel(transports_[channelId], compressor_); - - break; - } - case channel_media: - { - channels_[channelId] = new MediaChannel(transports_[channelId], compressor_); - - break; - } - case channel_http: - { - channels_[channelId] = new HttpChannel(transports_[channelId], compressor_); - - break; - } - case channel_font: - { - channels_[channelId] = new FontChannel(transports_[channelId], compressor_); - - break; - } - default: - { - channels_[channelId] = new SlaveChannel(transports_[channelId], compressor_); - - break; - } - } - - if (channels_[channelId] == NULL) - { - deallocateTransport(channelId); - - return -1; - } - - #ifdef TEST - *logofs << "Proxy: Accepted new connection to " - << label << " server.\n" << logofs_flush; - #endif - - cerr << "Info" << ": Accepted new connection to " - << label << " server.\n"; - - increaseChannels(channelId); - - switch (type) - { - case channel_cups: - { - if (handleControl(code_new_cups_connection, channelId) < 0) - { - return -1; - } - - break; - } - case channel_smb: - { - if (handleControl(code_new_smb_connection, channelId) < 0) - { - return -1; - } - - break; - } - case channel_media: - { - if (handleControl(code_new_media_connection, channelId) < 0) - { - return -1; - } - - break; - } - case channel_http: - { - if (handleControl(code_new_http_connection, channelId) < 0) - { - return -1; - } - - break; - } - case channel_font: - { - if (handleControl(code_new_font_connection, channelId) < 0) - { - return -1; - } - - break; - } - default: - { - if (handleControl(code_new_slave_connection, channelId) < 0) - { - return -1; - } - - break; - } - } - - channels_[channelId] -> handleConfiguration(); - - return 1; -} - -int Proxy::handleNewSlaveConnection(int clientFd) -{ - // Since ProtoStep7 (#issue 108) - return handleNewGenericConnection(clientFd, channel_slave, "slave"); -} - - - -int Proxy::handleNewGenericConnectionFromProxy(int channelId, T_channel_type type, - ChannelEndPoint &endPoint, const char *label) -{ - char *unixPath, *host; - long port; - - if (endPoint.getUnixPath(&unixPath)) { - return handleNewGenericConnectionFromProxyUnix(channelId, type, unixPath, label); - } - - if (endPoint.getTCPHostAndPort(&host, &port)) { - return handleNewGenericConnectionFromProxyTCP(channelId, type, host, port, label); - } - - #ifdef WARNING - *logofs << "Proxy: WARNING! Refusing attempted connection " - << "to " << label << " server.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Refusing attempted connection " - << "to " << label << " server.\n"; - - return -1; -} - -int Proxy::handleNewGenericConnectionFromProxyTCP(int channelId, T_channel_type type, - const char *hostname, long port, const char *label) - -{ - if (port <= 0) - { - // - // This happens when user has disabled - // forwarding of the specific service. - // - - #ifdef WARNING - *logofs << "Proxy: WARNING! Refusing attempted connection " - << "to " << label << " server.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Refusing attempted connection " - << "to " << label << " server.\n"; - - return -1; - } - - const char *serverHost = hostname; - int serverAddrFamily = AF_INET; - sockaddr *serverAddr = NULL; - unsigned int serverAddrLength = 0; - - #ifdef TEST - *logofs << "Proxy: Connecting to " << label - << " server '" << serverHost << "' on TCP port '" - << port << "'.\n" << logofs_flush; - #endif - - int serverIPAddr = GetHostAddress(serverHost); - - if (serverIPAddr == 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Unknown " << label - << " server host '" << serverHost << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Unknown " << label - << " server host '" << serverHost - << "'.\n"; - - return -1; - } - - sockaddr_in *serverAddrTCP = new sockaddr_in; - - serverAddrTCP -> sin_family = AF_INET; - serverAddrTCP -> sin_port = htons(port); - serverAddrTCP -> sin_addr.s_addr = serverIPAddr; - - serverAddr = (sockaddr *) serverAddrTCP; - serverAddrLength = sizeof(sockaddr_in); - - // - // Connect to the requested server. - // - - int serverFd = socket(serverAddrFamily, SOCK_STREAM, PF_UNSPEC); - - if (serverFd < 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Call to socket failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to socket failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - delete serverAddrTCP; - - return -1; - } - else if (connect(serverFd, serverAddr, serverAddrLength) < 0) - { - #ifdef WARNING - *logofs << "Proxy: WARNING! Connection to " << label - << " server '" << serverHost << ":" << port - << "' failed with error '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Connection to " << label - << " server '" << serverHost << ":" << port - << "' failed with error '" << ESTR() << "'.\n"; - - close(serverFd); - - delete serverAddrTCP; - - return -1; - } - - delete serverAddrTCP; - - if (handlePostConnectionFromProxy(channelId, serverFd, type, label) < 0) - { - return -1; - } - - #ifdef TEST - *logofs << "Proxy: Forwarded new connection to " - << label << " server on port '" << port - << "'.\n" << logofs_flush; - #endif - - cerr << "Info" << ": Forwarded new connection to " - << label << " server on port '" << port - << "'.\n"; - - return 1; -} - -int Proxy::handleNewGenericConnectionFromProxyUnix(int channelId, T_channel_type type, - const char *path, const char *label) -{ - if (path == NULL || *path == '\0' ) - { - // - // This happens when user has disabled - // forwarding of the specific service. - // - - #ifdef WARNING - *logofs << "Proxy: WARNING! Refusing attempted connection " - << "to " << label << " server.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Refusing attempted connection " - << "to " << label << " server.\n"; - - return -1; - } - - sockaddr_un serverAddrUnix; - - unsigned int serverAddrLength = sizeof(sockaddr_un); - - int serverAddrFamily = AF_UNIX; - - serverAddrUnix.sun_family = AF_UNIX; - - const int serverAddrNameLength = 108; - - strncpy(serverAddrUnix.sun_path, path, serverAddrNameLength); - - *(serverAddrUnix.sun_path + serverAddrNameLength - 1) = '\0'; - - #ifdef TEST - *logofs << "Proxy: Connecting to " << label << " server " - << "on Unix port '" << path << "'.\n" << logofs_flush; - #endif - - // - // Connect to the requested server. - // - - int serverFd = socket(serverAddrFamily, SOCK_STREAM, PF_UNSPEC); - - if (serverFd < 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! Call to socket failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to socket failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - return -1; - } - else if (connect(serverFd, (sockaddr *) &serverAddrUnix, serverAddrLength) < 0) - { - #ifdef WARNING - *logofs << "Proxy: WARNING! Connection to " << label - << " server on Unix port '" << path << "' failed " - << "with error " << EGET() << ", '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Connection to " << label - << " server on Unix port '" << path << "' failed " - << "with error " << EGET() << ", '" << ESTR() << "'.\n"; - - close(serverFd); - - return -1; - } - - if (handlePostConnectionFromProxy(channelId, serverFd, type, label) < 0) - { - return -1; - } - - #ifdef TEST - *logofs << "Proxy: Forwarded new connection to " - << label << " server on Unix port '" << path - << "'.\n" << logofs_flush; - #endif - - cerr << "Info" << ": Forwarded new connection to " - << label << " server on Unix port '" << path - << "'.\n"; - - return 1; -} - -int Proxy::handleNewSlaveConnectionFromProxy(int channelId) -{ - - cerr << "Info" << ": New slave connection on " - << "channel ID#" << channelId << "\n"; - - char *nx_slave_cmd = getenv("NX_SLAVE_CMD"); - if (nx_slave_cmd == NULL) { - return -1; - } - - int spair[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, spair) == -1) { - perror("socketpair"); - return -1; - } - - int serverFd = spair[0]; - int clientFd = spair[1]; - - if (handlePostConnectionFromProxy(channelId, serverFd, channel_slave, "slave") < 0) - { - close(serverFd); - close(clientFd); - return -1; - } - - - int pid = fork(); - if (pid == 0) - { - - if (dup2(clientFd, 0) == -1) - { - perror("dup2"); - exit(1); - } - - if (dup2(clientFd, 1) == -1) - { - perror("dup2"); - exit(1); - } - - close(serverFd); - close(clientFd); - - /* Close FDs used by NX, QVD #1208 */ - for (int fd = 3; fd < 256; fd++) { - close(fd); - } - - char *const argv[2] = {nx_slave_cmd, NULL}; - - if (execv(nx_slave_cmd, argv) == -1) - { - perror("execv"); - } - exit(1); - - } - else if (pid == -1) - { - // TODO Test this! - perror("fork"); - close(serverFd); - close(clientFd); - return -1; - } - - close(clientFd); - slavePidMap_[channelId] = pid; - - cerr << "Info" << ": slave channel ID#" << channelId << " handler has PID " << pid << endl; - - return 1; -} - -void Proxy::checkSlaves() -{ - for (int channelId = 0; channelId 1 && HandleChild(pid)) - { - slavePidMap_[channelId] = nothing; - cerr << "Info:" << " Handled death of slave with pid " << pid << endl; - } - } -} - -int Proxy::handlePostConnectionFromProxy(int channelId, int serverFd, - T_channel_type type, const char *label) -{ - // - // Turn queuing off for path proxy-to-server. - // - - SetNoDelay(serverFd, 1); - - assignChannelMap(channelId, serverFd); - - #ifdef TEST - *logofs << "Proxy: Descriptor FD#" << serverFd - << " mapped to channel ID#" << channelId << ".\n" - << logofs_flush; - #endif - - if (allocateTransport(serverFd, channelId) < 0) - { - return -1; - } - - switch (type) - { - case channel_cups: - { - channels_[channelId] = new CupsChannel(transports_[channelId], compressor_); - break; - } - case channel_smb: - { - channels_[channelId] = new SmbChannel(transports_[channelId], compressor_); - - break; - } - case channel_media: - { - channels_[channelId] = new MediaChannel(transports_[channelId], compressor_); - - break; - } - case channel_http: - { - channels_[channelId] = new HttpChannel(transports_[channelId], compressor_); - - break; - } - case channel_font: - { - channels_[channelId] = new FontChannel(transports_[channelId], compressor_); - - break; - } - default: - { - channels_[channelId] = new SlaveChannel(transports_[channelId], compressor_); - - break; - } - } - - if (channels_[channelId] == NULL) - { - deallocateTransport(channelId); - - return -1; - } - - increaseChannels(channelId); - - channels_[channelId] -> handleConfiguration(); - - return 1; -} diff --git a/nxcomp/Proxy.h b/nxcomp/Proxy.h deleted file mode 100644 index ea60c827a..000000000 --- a/nxcomp/Proxy.h +++ /dev/null @@ -1,1276 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Proxy_H -#define Proxy_H - -#include - -#ifdef _AIX -#include -#endif - -#include "Misc.h" -#include "Timestamp.h" - -#include "List.h" -#include "Channel.h" -#include "Transport.h" -#include "EncodeBuffer.h" -#include "ProxyReadBuffer.h" -#include "ChannelEndPoint.h" - -// -// Forward declaration as we -// need a pointer. -// - -class Agent; - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Log the important tracepoints related -// to writing packets to the peer proxy. -// - -#undef FLUSH - -// -// Codes used for control messages in -// proxy-to-proxy protocol. -// -// The following codes are currently -// unused. -// -// code_alert_reply, -// code_reset_request, -// code_reset_reply, -// code_load_reply, -// code_save_reply, -// code_shutdown_reply, -// code_configuration_request, -// code_configuration_reply. -// -// These are for compatibility with -// old versions. -// -// code_sync_request, -// code_sync_reply, -// -// The code_new_aux_connection should not -// be used anymore. Auxiliary X connections -// are treated as normal X channels since -// version 1.5.0. -// - -typedef enum -{ - code_new_x_connection, - code_new_cups_connection, - code_new_aux_connection, - code_new_smb_connection, - code_new_media_connection, - code_switch_connection, - code_drop_connection, - code_finish_connection, - code_begin_congestion, - code_end_congestion, - code_alert_request, - code_alert_reply, - code_reset_request, - code_reset_reply, - code_load_request, - code_load_reply, - code_save_request, - code_save_reply, - code_shutdown_request, - code_shutdown_reply, - code_control_token_request, - code_control_token_reply, - code_configuration_request, - code_configuration_reply, - code_statistics_request, - code_statistics_reply, - code_new_http_connection, - code_sync_request, - code_sync_reply, - code_new_font_connection, - code_new_slave_connection, - code_finish_listeners, - code_split_token_request, - code_split_token_reply, - code_data_token_request, - code_data_token_reply, - code_last_tag - -} T_proxy_code; - -typedef enum -{ - operation_in_negotiation, - operation_in_messages, - operation_in_configuration, - operation_in_statistics, - operation_last_tag - -} T_proxy_operation; - -typedef enum -{ - frame_ping, - frame_data, - -} T_frame_type; - -typedef enum -{ - token_control, - token_split, - token_data - -} T_token_type; - -typedef enum -{ - load_if_any, - load_if_first - -} T_load_type; - -class Proxy -{ - public: - - // - // Maximum number of supported channels. - // - - static const int CONNECTIONS_LIMIT = 256; - - // - // Numboer of token types. - // - - static const int TOKEN_TYPES = 3; - - // - // Lenght of buffer we use to add our - // control messages plus the length of - // the data frame. - // - - static const int CONTROL_CODES_LENGTH = ENCODE_BUFFER_PREFIX_SIZE - 5; - - static const int CONTROL_CODES_THRESHOLD = CONTROL_CODES_LENGTH - 9; - - Proxy(int fd); - - virtual ~Proxy(); - - // - // Inform the proxy that the negotiation phase is - // completed and that it can start handling binary - // messages. - // - - int setOperational(); - - int getOperational() - { - return (operation_ != operation_in_negotiation); - } - - int setReadDescriptors(fd_set *fdSet, int &fdMax, T_timestamp &tsMax); - - int setWriteDescriptors(fd_set *fdSet, int &fdMax, T_timestamp &tsMax); - - // - // Perform the operation on the proxy - // link or its own channels. - // - - int handleRead(int &resultFds, fd_set &fdSet); - - int handleFlush(int &resultFds, fd_set &fdSet); - - int handleRead(); - - int handleRead(int fd, const char *data = NULL, int size = 0); - - int handleEvents(); - - int handleFlush(); - - int handleFlush(int fd); - - int handlePing(); - - int handleFinish(); - - int handleShutdown(); - - int handleStatistics(int type, ostream *statofs); - - int handleAlert(int alert); - - int handleRotate() - { - activeChannels_.rotate(); - - return 1; - } - - int handleChannelConfiguration(); - - int handleSocketConfiguration(); - - int handleLinkConfiguration(); - - int handleCacheConfiguration(); - - // - // These must be called just after initialization to - // tell to the proxy where the network connections - // have to be forwarded. - // - - virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, - sockaddr * xServerAddr, unsigned int xServerAddrLength) = 0; - - virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort, - ChannelEndPoint &smbServerPort, - ChannelEndPoint &mediaServerPort, - ChannelEndPoint &httpServerPort, - const char *fontServerPort) = 0; - - // - // Create new tunneled channels. - // - - virtual int handleNewConnection(T_channel_type type, int clientFd) = 0; - - virtual int handleNewConnectionFromProxy(T_channel_type type, int channelId) = 0; - - virtual int handleNewAgentConnection(Agent *agent) = 0; - - virtual int handleNewXConnection(int clientFd) = 0; - - virtual int handleNewXConnectionFromProxy(int channelId) = 0; - - int handleNewGenericConnection(int clientFd, T_channel_type type, const char *label); - - int handleNewGenericConnectionFromProxy(int channelId, T_channel_type type, - ChannelEndPoint &endpoint, const char *label); - - int handleNewGenericConnectionFromProxyUnix(int channelId, T_channel_type type, - const char *path, const char *label); - - int handleNewGenericConnectionFromProxyTCP(int channelId, T_channel_type type, - const char *hostname, long port, const char *label); - - int handleNewSlaveConnection(int clientFd); - - int handleNewSlaveConnectionFromProxy(int channelId); - - void checkSlaves(); - - // - // Force closure of channels. - // - - int handleCloseConnection(int clientFd); - - int handleCloseAllXConnections(); - - int handleCloseAllListeners(); - - // - // Called when the loop has replaced - // or closed a previous alert. - // - - void handleResetAlert(); - - // - // Handle the persistent cache. - // - - virtual int handleLoad(T_load_type type) = 0; - - virtual int handleSave() = 0; - - protected: - - // - // Timeout related data: - // - // flush - // split - // motion - // - // Timeouts in milliseconds after which the - // proxy will have to perform the operation. - // - // readTs, writeTs - // - // Timestamp of last packet received or sent - // to remote proxy. Used to detect lost con- - // nection. - // - // loopTs - // - // Timestamp of last loop completed by the - // proxy - // - // pingTs - // - // Timestamp of last ping request sent to the - // remote peer. - // - // alertTs - // - // Timestamp of last 'no data received' alert - // dialog shown to the user. - // - // loadTs - // - // Were message stores populated from data on - // disk. - // - // splitTs - // motionTs - // - // Timestamps of the last operation of this - // kind handled by the proxy. - // - - typedef struct - { - int split; - int motion; - - T_timestamp readTs; - T_timestamp writeTs; - - T_timestamp loopTs; - T_timestamp pingTs; - T_timestamp alertTs; - T_timestamp loadTs; - - T_timestamp splitTs; - T_timestamp motionTs; - - } T_proxy_timeouts; - - // - // Bytes accumulated so far while waiting - // to send the next token, number of tokens - // remaining for each token type and other - // token related information. - // - - typedef struct - { - int size; - int limit; - - int bytes; - int remaining; - - T_proxy_code request; - T_proxy_code reply; - - T_token_type type; - - } T_proxy_token; - - int handlePostConnectionFromProxy(int channelId, int serverFd, - T_channel_type type, const char *label); - - int handleDrain(); - - int handleFrame(T_frame_type type); - - int handleFinish(int channelId); - - int handleDrop(int channelId); - - int handleFinishFromProxy(int channelId); - - int handleDropFromProxy(int channelId); - - int handleStatisticsFromProxy(int type); - - int handleStatisticsFromProxy(const unsigned char *message, unsigned int length); - - int handleNegotiation(const unsigned char *message, unsigned int length); - - int handleNegotiationFromProxy(const unsigned char *message, unsigned int length); - - int handleToken(T_frame_type type); - - int handleTokenFromProxy(T_proxy_token &token, int count); - - int handleTokenReplyFromProxy(T_proxy_token &token, int count); - - int handleSyncFromProxy(int channelId); - - int handleSwitch(int channelId); - - int handleControl(T_proxy_code code, int data = -1); - - int handleControlFromProxy(const unsigned char *message); - - // - // Interleave reads of the X server - // events while writing data to the - // remote proxy. - // - - virtual int handleAsyncEvents() = 0; - - // - // Timer related functions. - // - - protected: - - void setTimer(int value) - { - SetTimer(value); - } - - void resetTimer() - { - ResetTimer(); - - timer_ = 0; - } - - public: - - void handleTimer() - { - timer_ = 1; - } - - int getTimer() - { - return timer_; - } - - // - // Can the channel consume data and the - // proxy produce more output? - // - - int canRead(int fd) const - { - return (isTimeToRead() == 1 && - isTimeToRead(getChannel(fd)) == 1); - } - - // - // Can the proxy read more data from its - // peer? - // - - int canRead() const - { - return (transport_ -> readable() != 0); - } - - int canFlush() const - { - return (encodeBuffer_.getLength() + - controlLength_ + transport_ -> length() + - transport_ -> flushable() > 0); - } - - int needFlush(int channelId) const - { - return (outputChannel_ == channelId && - encodeBuffer_.getLength() > 0); - } - - int needFlush() const - { - return (encodeBuffer_.getLength() > 0); - } - - int shouldFlush() const - { - if ((int) ((encodeBuffer_.getLength() + - controlLength_) / statistics -> - getStreamRatio()) >= control -> TokenSize) - { - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "Proxy: FLUSH! Requesting a flush with " - << (encodeBuffer_.getLength() + controlLength_) - << " bytes and stream ratio " << (double) statistics -> - getStreamRatio() << ".\n" << logofs_flush; - #endif - - return 1; - } - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "Proxy: Not requesting a flush with " - << (encodeBuffer_.getLength() + controlLength_) - << " bytes and stream ratio " << (double) statistics -> - getStreamRatio() << ".\n" << logofs_flush; - #endif - - return 0; - } - - int needDrain() const - { - return (congestion_ == 1 || transport_ -> length() > - control -> TransportProxyBufferThreshold); - } - - int getFd() const - { - return fd_; - } - - int getFlushable(int fd) const - { - if (fd == fd_) - { - return (encodeBuffer_.getLength() + controlLength_ + - transport_ -> flushable()); - } - - return 0; - } - - int getSplitSize() - { - return (clientStore_ != NULL ? clientStore_ -> - getSplitTotalSize() : 0); - } - - int getSplitStorageSize() - { - return (clientStore_ != NULL ? clientStore_ -> - getSplitTotalStorageSize() : 0); - } - - // - // Returns the number of active channels - // that currently managed by this proxy. - // - - int getChannels(T_channel_type type = channel_none); - - // - // If descriptor corresponds to a valid - // channel, returns the type of traffic - // carried by it. - // - - T_channel_type getType(int fd); - - // - // Given a channel type, returns the - // literal name. - // - - const char *getTypeName(T_channel_type type); - - // - // Get a convenient name for 'localhost'. - // - - const char *getComputerName(); - - // - // Set if we have initiated the shutdown - // procedure and if the shutdown request - // has been received from the remote. - // - - int getFinish() const - { - return finish_; - } - - int getShutdown() const - { - return shutdown_; - } - - // - // Interfaces to the transport buffers. - // - - int getLength(int fd) const - { - if (fd == fd_) - { - return transport_ -> length(); - } - - int channelId = getChannel(fd); - - if (channelId < 0 || channels_[channelId] == NULL) - { - return 0; - } - - return transports_[channelId] -> length(); - } - - int getPending(int fd) const - { - if (fd == fd_) - { - return transport_ -> pending(); - } - - int channelId = getChannel(fd); - - if (channelId < 0 || channels_[channelId] == NULL) - { - return 0; - } - - return transports_[channelId] -> pending(); - } - - // - // Check if the proxy or the given channel - // has data in the buffer because of a - // blocking write. - // - - int getBlocked(int fd) const - { - if (fd == fd_) - { - return transport_ -> blocked(); - } - - int channelId = getChannel(fd); - - if (channelId < 0 || channels_[channelId] == NULL) - { - return 0; - } - - return transports_[channelId] -> blocked(); - } - - // - // Check if the proxy or the given channel has - // data to read. - // - - int getReadable(int fd) const - { - if (fd == fd_) - { - return transport_ -> readable(); - } - - int channelId = getChannel(fd); - - if (channelId < 0 || channels_[channelId] == NULL) - { - return 0; - } - - return transports_[channelId] -> readable(); - } - - // - // Return a vale between 0 and 9 in the case - // of the proxy descriptor. - // - - int getCongestion(int fd) const - { - if (fd == fd_) - { - return (agent_ != nothing && congestions_[agent_] == 1 ? 9 : - (int) statistics -> getCongestionInFrame()); - } - - int channelId = getChannel(fd); - - if (channelId < 0 || channels_[channelId] == NULL) - { - return 0; - } - - return channels_[channelId] -> getCongestion(); - } - - // - // Let the statistics class get info - // from the message stores. - // - - const ClientStore * const getClientStore() const - { - return clientStore_; - } - - const ServerStore * const getServerStore() const - { - return serverStore_; - } - - // - // These can be called asynchronously by - // channels during their read or write - // loop. - // - - int handleAsyncRead(int fd) - { - return handleRead(fd); - } - - int handleAsyncCongestion(int fd) - { - int channelId = getChannel(fd); - - return handleControl(code_begin_congestion, channelId); - } - - int handleAsyncDecongestion(int fd) - { - int channelId = getChannel(fd); - - return handleControl(code_end_congestion, channelId); - } - - int handleAsyncSplit(int fd, Split *split) - { - return channels_[getChannel(fd)] -> - handleSplitEvent(encodeBuffer_, split); - } - - int handleAsyncPriority() - { - if (control -> FlushPriority == 1) - { - return handleFlush(); - } - - return 0; - } - - int canAsyncFlush() const - { - return shouldFlush(); - } - - int handleAsyncFlush() - { - return handleFlush(); - } - - int handleAsyncSwitch(int fd) - { - return handleSwitch(getChannel(fd)); - } - - int handleAsyncKeeperCallback() - { - KeeperCallback(); - - return 1; - } - - // - // Internal interfaces used to verify the - // availability of channels and the proxy - // link. - // - - protected: - - int isTimeToRead() const - { - if (congestion_ == 0 && transport_ -> - blocked() == 0) - { - return 1; - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Can't read from channels " - << "with congestion " << congestion_ - << " and blocked " << transport_ -> - blocked() << ".\n" << logofs_flush; - #endif - - return 0; - } - } - - int isTimeToRead(int channelId) const - { - if (channelId >= 0 && channelId < CONNECTIONS_LIMIT && - channels_[channelId] != NULL && - congestions_[channelId] == 0) - { - if (channels_[channelId] -> getType() == channel_x11 || - tokens_[token_data].remaining > 0 || - channels_[channelId] -> - getFinish() == 1) - { - return 1; - } - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: Can't read from generic " - << "descriptor FD#" << getFd(channelId) - << " channel ID#" << channelId << " with " - << tokens_[token_data].remaining - << " data tokens remaining.\n" - << logofs_flush; - #endif - - return 0; - } - - #if defined(TEST) || defined(INFO) - - if (channelId < 0 || channelId >= CONNECTIONS_LIMIT || - channels_[channelId] == NULL) - { - *logofs << "Proxy: WARNING! No valid channel for ID#" - << channelId << ".\n" << logofs_flush; - } - else if (channels_[channelId] -> getFinish()) - { - *logofs << "Proxy: Can't read from finishing " - << "descriptor FD#" << getFd(channelId) - << " channel ID#" << channelId << ".\n" - << logofs_flush; - } - else if (congestions_[channelId] == 1) - { - *logofs << "Proxy: Can't read from congested " - << "descriptor FD#" << getFd(channelId) - << " channel ID#" << channelId << ".\n" - << logofs_flush; - } - - #endif - - return 0; - } - - // - // Handle the flush and split timeouts. - // All these functions should round up - // to the value of the latency timeout - // to save a further loop. - // - - protected: - - int isTimeToSplit() const - { - if (isTimestamp(timeouts_.splitTs) && - getTimeToNextSplit() <= control -> - LatencyTimeout) - { - if (tokens_[token_split].remaining > 0) - { - return 1; - } - - #if defined(TEST) || defined(INFO) - *logofs << "Proxy: WARNING! Can't encode splits " - << "with " << tokens_[token_split].remaining - << " split tokens remaining.\n" - << logofs_flush; - #endif - } - - return 0; - } - - int isTimeToMotion() const - { - return (isTimestamp(timeouts_.motionTs) && - getTimeToNextMotion() <= control -> - LatencyTimeout); - } - - int getTimeToNextSplit() const - { - #if defined(TEST) || defined(INFO) || defined(FLUSH) - - if (isTimestamp(timeouts_.splitTs) == 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! No split timeout was set " - << "for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": No split timeout was set " - << "for proxy FD#" << fd_ << ".\n"; - - HandleCleanup(); - } - - #endif - - int diffTs = timeouts_.split - - diffTimestamp(timeouts_.splitTs, - getTimestamp()); - - return (diffTs > 0 ? diffTs : 0); - } - - int getTimeToNextMotion() const - { - #if defined(TEST) || defined(INFO) || defined(FLUSH) - - if (isTimestamp(timeouts_.motionTs) == 0) - { - #ifdef PANIC - *logofs << "Proxy: PANIC! No motion timeout was set " - << "for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": No motion timeout was set " - << "for proxy FD#" << fd_ << ".\n"; - - HandleCleanup(); - } - - #endif - - int diffTs = timeouts_.motion - - diffTimestamp(timeouts_.motionTs, - getTimestamp()); - - return (diffTs > 0 ? diffTs : 0); - } - - protected: - - // - // Implement persistence of cache on disk. - // - - virtual int handleLoadFromProxy() = 0; - virtual int handleSaveFromProxy() = 0; - - int handleLoadStores(); - int handleSaveStores(); - - char *handleSaveAllStores(const char *savePath, bool & isTooSmall) const; - - virtual int handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient) const = 0; - - int handleSaveVersion(unsigned char *buffer, int &major, int &minor, int &patch) const; - - void handleFailOnSave(const char *fullName, const char *failContext) const; - - const char *handleLoadAllStores(const char *loadPath, const char *loadName) const; - - virtual int handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const = 0; - - int handleLoadVersion(const unsigned char *buffer, int &major, int &minor, int &patch) const; - - void handleFailOnLoad(const char *fullName, const char *failContext) const; - - // - // Prepare for a new persistent cache. - // - - int handleResetPersistentCache(); - - // - // Reset the stores in the case of a - // failure loading the cache. - // - - int handleResetStores(); - - // - // Reset the transport buffer and the - // other counters. - // - - void handleResetFlush(); - - // - // Utility functions used to map file - // descriptors to channel ids. - // - - protected: - - int allocateChannelMap(int fd); - int checkChannelMap(int channelId); - int assignChannelMap(int channelId, int fd); - - void cleanupChannelMap(int channelId); - - virtual int checkLocalChannelMap(int channelId) = 0; - - int addControlCodes(T_proxy_code code, int data); - int addTokenCodes(T_proxy_token &token); - - int getFd(int channelId) const - { - if (channelId >= 0 && channelId < CONNECTIONS_LIMIT) - { - return fdMap_[channelId]; - } - - return -1; - } - - int getChannel(int fd) const - { - if (fd >= 0 && fd < CONNECTIONS_LIMIT) - { - return channelMap_[fd]; - } - - return -1; - } - - protected: - - void setSplitTimeout(int channelId); - void setMotionTimeout(int channelId); - - void increaseChannels(int channelId); - void decreaseChannels(int channelId); - - int allocateTransport(int channelFd, int channelId); - int deallocateTransport(int channelId); - - // - // The proxy has its own transport. - // - - ProxyTransport *transport_; - - // - // The static compressor is shared among - // channels and all the message stores. - // - - StaticCompressor *compressor_; - - // - // Map NX specific opcodes. - // - - OpcodeStore *opcodeStore_; - - // - // Stores are shared between channels. - // - - ClientStore *clientStore_; - ServerStore *serverStore_; - - // - // Client and server caches are shared - // between channels. - // - - ClientCache *clientCache_; - ServerCache *serverCache_; - - // - // The proxy's file descriptor. - // - - int fd_; - - // - // Channels currently selected for I/O - // operations. - // - - int inputChannel_; - int outputChannel_; - - // - // List of active channels. - // - - List activeChannels_; - - // - // Used to read data sent from peer proxy. - // - - ProxyReadBuffer readBuffer_; - - // - // Used to send data to peer proxy. - // - - EncodeBuffer encodeBuffer_; - - // - // Control messages' array. - // - - int controlLength_; - - unsigned char controlCodes_[CONTROL_CODES_LENGTH]; - - // - // Table of channel classes taking - // care of open X connections. - // - - Channel *channels_[CONNECTIONS_LIMIT]; - - // - // Table of open sockets. - // - - Transport *transports_[CONNECTIONS_LIMIT]; - - // - // Timeout related data. - // - - T_proxy_timeouts timeouts_; - - // - // Proxy can be decoding messages, - // handling a link reconfiguration, - // or decoding statistics. - // - - int operation_; - - // - // True if we are currently draining - // the proxy link. - // - - int draining_; - - // - // Force flush because of prioritized - // control messages to send. - // - - int priority_; - - // - // Set if we have initiated the close - // down procedure. - // - - int finish_; - - // - // Remote peer requested the shutdown. - // - - int shutdown_; - - // - // We are in the middle of a network - // congestion in the path to remote - // proxy. - // - - int congestion_; - - // - // Channels at the remote end that - // are not consuming their data. - // - - int congestions_[CONNECTIONS_LIMIT]; - - // - // Is the timer expired? - // - - int timer_; - - // - // Did the proxy request an alert? - // - - int alert_; - - // - // The channel id of the agent. - // - - int agent_; - - // - // Token related data. - // - - T_proxy_token tokens_[TOKEN_TYPES]; - - // - // Pointer to stream descriptor where - // proxy is producing statistics. - // - - ostream *currentStatistics_; - - private: - - // - // Map channel ids to file descriptors. - // - - int channelMap_[CONNECTIONS_LIMIT]; - int fdMap_[CONNECTIONS_LIMIT]; - int slavePidMap_[CONNECTIONS_LIMIT]; -}; - -#endif /* Proxy_H */ diff --git a/nxcomp/ProxyReadBuffer.cpp b/nxcomp/ProxyReadBuffer.cpp deleted file mode 100644 index 0427bb76c..000000000 --- a/nxcomp/ProxyReadBuffer.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ProxyReadBuffer.h" - -#include "Transport.h" - -// -// Set the verbosity level. You also -// need to define DUMP in Misc.cpp -// if DUMP is defined here. -// - -#define WARNING -#define PANIC -#undef TEST -#undef DEBUG -#undef DUMP - -unsigned int ProxyReadBuffer::suggestedLength(unsigned int pendingLength) -{ - // - // Always read all the data that - // is available. - // - - int readable = transport_ -> readable(); - - unsigned int readLength = (readable == -1 ? 0 : (unsigned int) readable); - - if (readLength < pendingLength) - { - readLength = pendingLength; - } - - // - // Even if the readable data is not - // enough to make a complete message, - // resize the buffer to accommodate - // it all. - // - - if (pendingLength < remaining_) - { - readLength = remaining_; - } - - return readLength; -} - -int ProxyReadBuffer::locateMessage(const unsigned char *start, - const unsigned char *end, - unsigned int &controlLength, - unsigned int &dataLength, - unsigned int &trailerLength) -{ - unsigned int lengthLength = 0; - const unsigned char *nextSrc = start; - unsigned char next; - - dataLength = 0; - - #ifdef TEST - *logofs << "ProxyReadBuffer: Locating message for FD#" - << transport_ -> fd() << " with " << end - start - << " bytes.\n" << logofs_flush; - #endif - - // - // Use something like the following if - // you are looking for errors. - // - - #ifdef DUMP - if (control -> ProxyMode == proxy_server && start < end && - transport_ -> fd() == 6 || transport_ -> fd() == 11) - { - *logofs << "ProxyReadBuffer: Partial checksums are:\n"; - - DumpBlockChecksums(start, end - start, 256); - - *logofs << logofs_flush; - } - #endif - - do - { - if (nextSrc >= end) - { - remaining_ = 1; - - #ifdef TEST - *logofs << "ProxyReadBuffer: No message was located " - << "with remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - - next = *nextSrc++; - - dataLength <<= 7; - dataLength |= (unsigned int) (next & 0x7f); - - lengthLength++; - } - while (next & 0x80); - - unsigned int totalLength; - - if (dataLength == 0) - { - trailerLength = 0; - controlLength = 3; - totalLength = controlLength; - } - else - { - trailerLength = lengthLength; - controlLength = 0; - totalLength = dataLength + trailerLength; - } - - if (start + totalLength > end) - { - // - // When having to decompress a ZLIB stream, - // a single byte can be enough to complete - // the frame. - // - - if (control -> RemoteStreamCompression == 0) - { - remaining_ = totalLength - (end - start); - } - else - { - remaining_ = 1; - } - - #ifdef TEST - *logofs << "ProxyReadBuffer: No message was located " - << "with remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - else - { - #ifdef DUMP - *logofs << "ProxyReadBuffer: Received " << totalLength << " bytes of data " - << "with checksum "; - - DumpChecksum(start, totalLength); - - *logofs << " on proxy FD#" << transport_ -> fd() << ".\n" << logofs_flush; - #endif - - #if defined(TEST) || defined(INFO) - *logofs << "ProxyReadBuffer: Produced plain input for " << dataLength - << "+" << trailerLength << "+" << controlLength << " bytes out of " - << totalLength << " bytes.\n" << logofs_flush; - #endif - - #ifdef DUMP - *logofs << "ProxyReadBuffer: Partial checksums are:\n"; - - DumpBlockChecksums(start, totalLength, 256); - - *logofs << logofs_flush; - #endif - - remaining_ = 0; - - #ifdef TEST - *logofs << "ProxyReadBuffer: Located message with " - << "remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 1; - } -} diff --git a/nxcomp/ProxyReadBuffer.h b/nxcomp/ProxyReadBuffer.h deleted file mode 100644 index 68e9e95fa..000000000 --- a/nxcomp/ProxyReadBuffer.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ProxyReadBuffer_H -#define ProxyReadBuffer_H - -#include "ReadBuffer.h" -#include "Control.h" - -class ProxyReadBuffer : public ReadBuffer -{ - public: - - ProxyReadBuffer(Transport *transport) - - : ReadBuffer(transport) - { - } - - virtual ~ProxyReadBuffer() - { - } - - protected: - - virtual unsigned int suggestedLength(unsigned int pendingLength); - - virtual int locateMessage(const unsigned char *start, - const unsigned char *end, - unsigned int &controlLength, - unsigned int &dataLength, - unsigned int &trailerLength); -}; - -#endif /* ProxyReadBuffer_H */ diff --git a/nxcomp/PutImage.cpp b/nxcomp/PutImage.cpp deleted file mode 100644 index 7b9a3ae5d..000000000 --- a/nxcomp/PutImage.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PutImage.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -PutImageStore::PutImageStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = PUTIMAGE_ENABLE_CACHE; - enableData = PUTIMAGE_ENABLE_DATA; - - // Since ProtoStep7 (#issue 108) - enableCompress = PUTIMAGE_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = PUTIMAGE_DATA_LIMIT; - dataOffset = PUTIMAGE_DATA_OFFSET; - - cacheSlots = PUTIMAGE_CACHE_SLOTS; - cacheThreshold = PUTIMAGE_CACHE_THRESHOLD; - cacheLowerThreshold = PUTIMAGE_CACHE_LOWER_THRESHOLD; - - // Since ProtoStep8 (#issue 108) - enableSplit = PUTIMAGE_ENABLE_SPLIT_IF_PROTO_STEP_8; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -PutImageStore::~PutImageStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int PutImageStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; - #endif - - encodeBuffer.encodeValue(GetUINT(buffer + 2, bigEndian), 16, 8); - - encodeBuffer.encodeValue((unsigned int) buffer[1], 2); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> drawableCache); - encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), - clientCache -> gcCache); - - unsigned int width = GetUINT(buffer + 12, bigEndian); - encodeBuffer.encodeCachedValue(width, 16, - clientCache -> putImageWidthCache, 8); - - unsigned int height = GetUINT(buffer + 14, bigEndian); - encodeBuffer.encodeCachedValue(height, 16, - clientCache -> putImageHeightCache, 8); - - unsigned int x = GetUINT(buffer + 16, bigEndian); - int xDiff = x - clientCache -> putImageLastX; - clientCache -> putImageLastX = x; - encodeBuffer.encodeCachedValue(xDiff, 16, - clientCache -> putImageXCache, 8); - - unsigned int y = GetUINT(buffer + 18, bigEndian); - int yDiff = y - clientCache -> putImageLastY; - clientCache -> putImageLastY = y; - encodeBuffer.encodeCachedValue(yDiff, 16, - clientCache -> putImageYCache, 8); - - encodeBuffer.encodeCachedValue(buffer[20], 8, - clientCache -> putImageLeftPadCache); - - encodeBuffer.encodeCachedValue(buffer[21], 8, - clientCache -> depthCache); - - #ifdef DEBUG - *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int PutImageStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; - #endif - - unsigned int value; - unsigned char cValue; - - decodeBuffer.decodeValue(value, 16, 8); - - size = (value << 2); - - buffer = writeBuffer -> addMessage(size); - - decodeBuffer.decodeValue(value, 2); - buffer[1] = (unsigned char) value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - PutULONG(value, buffer + 4, bigEndian); - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - PutULONG(value, buffer + 8, bigEndian); - - unsigned int width; - decodeBuffer.decodeCachedValue(width, 16, - clientCache -> putImageWidthCache, 8); - PutUINT(width, buffer + 12, bigEndian); - - unsigned int height; - decodeBuffer.decodeCachedValue(height, 16, - clientCache -> putImageHeightCache, 8); - PutUINT(height, buffer + 14, bigEndian); - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageXCache, 8); - clientCache -> putImageLastX += value; - clientCache -> putImageLastX &= 0xffff; - PutUINT(clientCache -> putImageLastX, buffer + 16, bigEndian); - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageYCache, 8); - clientCache -> putImageLastY += value; - clientCache -> putImageLastY &= 0xffff; - PutUINT(clientCache -> putImageLastY, buffer + 18, bigEndian); - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> putImageLeftPadCache); - buffer[20] = cValue; - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - buffer[21] = cValue; - - #ifdef DEBUG - *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int PutImageStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PutImageMessage *putImage = (PutImageMessage *) message; - - // - // Here is the fingerprint. - // - - putImage -> format = *(buffer + 1); - putImage -> depth = *(buffer + 21); - putImage -> left_pad = *(buffer + 20); - - putImage -> width = GetUINT(buffer + 12, bigEndian); - putImage -> height = GetUINT(buffer + 14, bigEndian); - putImage -> pos_x = GetUINT(buffer + 16, bigEndian); - putImage -> pos_y = GetUINT(buffer + 18, bigEndian); - - putImage -> drawable = GetULONG(buffer + 4, bigEndian); - putImage -> gcontext = GetULONG(buffer + 8, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PutImageStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PutImageMessage *putImage = (PutImageMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = putImage -> format; - - PutULONG(putImage -> drawable, buffer + 4, bigEndian); - PutULONG(putImage -> gcontext, buffer + 8, bigEndian); - - PutUINT(putImage -> width, buffer + 12, bigEndian); - PutUINT(putImage -> height, buffer + 14, bigEndian); - PutUINT(putImage -> pos_x, buffer + 16, bigEndian); - PutUINT(putImage -> pos_y, buffer + 18, bigEndian); - - *(buffer + 20) = (unsigned char) putImage -> left_pad; - *(buffer + 21) = (unsigned char) putImage -> depth; - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PutImageStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PutImageMessage *putImage = (PutImageMessage *) message; - - *logofs << name() << ": Identity format " << (unsigned) putImage -> format - << ", depth " << (unsigned) putImage -> depth << ", left_pad " - << (unsigned) putImage -> left_pad << ", width " << putImage -> width - << ", height " << putImage -> height << ", pos_x " << putImage -> pos_x - << ", pos_y " << putImage -> pos_y << ", drawable " << putImage -> drawable - << ", gcontext " << putImage -> gcontext << ", size " << putImage -> size_ - << ".\n" << logofs_flush; - - #endif -} - -void PutImageStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Fields format, width, height, left_pad, depth. - // - - md5_append(md5_state_, buffer + 1, 1); - md5_append(md5_state_, buffer + 12, 4); - md5_append(md5_state_, buffer + 20, 2); -} - -void PutImageStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - // - // Encode the variant part. - // - - PutImageMessage *putImage = (PutImageMessage *) message; - PutImageMessage *cachedPutImage = (PutImageMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putImage -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(putImage -> drawable, clientCache -> drawableCache); - - cachedPutImage -> drawable = putImage -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putImage -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(putImage -> gcontext, clientCache -> gcCache); - - cachedPutImage -> gcontext = putImage -> gcontext; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putImage -> pos_x - << " as " << "pos_x" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_x = putImage -> pos_x - cachedPutImage -> pos_x; - - encodeBuffer.encodeCachedValue(diff_x, 16, - clientCache -> putImageXCache, 8); - - cachedPutImage -> pos_x = putImage -> pos_x; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putImage -> pos_y - << " as " << "pos_y" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_y = putImage -> pos_y - cachedPutImage -> pos_y; - - encodeBuffer.encodeCachedValue(diff_y, 16, - clientCache -> putImageYCache, 8); - - cachedPutImage -> pos_y = putImage -> pos_y; -} - -void PutImageStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - // - // Decode the variant part. - // - - PutImageMessage *putImage = (PutImageMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - putImage -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putImage -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - putImage -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putImage -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageXCache, 8); - - putImage -> pos_x += value; - putImage -> pos_x &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putImage -> pos_x - << " as pos_x field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageYCache, 8); - - putImage -> pos_y += value; - putImage -> pos_y &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putImage -> pos_y - << " as pos_y field.\n" << logofs_flush; - #endif -} diff --git a/nxcomp/PutImage.h b/nxcomp/PutImage.h deleted file mode 100644 index 93dde9dfb..000000000 --- a/nxcomp/PutImage.h +++ /dev/null @@ -1,172 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PutImage_H -#define PutImage_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define PUTIMAGE_ENABLE_CACHE 1 -#define PUTIMAGE_ENABLE_DATA 1 - -#define PUTIMAGE_DATA_LIMIT 262144 - 24 -#define PUTIMAGE_DATA_OFFSET 24 - -#define PUTIMAGE_CACHE_SLOTS 6000 -#define PUTIMAGE_CACHE_THRESHOLD 70 -#define PUTIMAGE_CACHE_LOWER_THRESHOLD 50 - -#define PUTIMAGE_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -#define PUTIMAGE_CACHE_THRESHOLD_IF_PACKED 10 -#define PUTIMAGE_CACHE_LOWER_THRESHOLD_IF_PACKED 5 - -#define PUTIMAGE_CACHE_THRESHOLD_IF_SHADOW 97 -#define PUTIMAGE_CACHE_LOWER_THRESHOLD_IF_SHADOW 90 - -#define PUTIMAGE_ENABLE_SPLIT_IF_PROTO_STEP_8 0 - -// -// The message class. -// - -class PutImageMessage : public Message -{ - friend class PutImageStore; - - public: - - PutImageMessage() - { - } - - ~PutImageMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char format; - unsigned char depth; - unsigned char left_pad; - unsigned short width; - unsigned short height; - unsigned int drawable; - unsigned int gcontext; - unsigned short pos_x; - unsigned short pos_y; -}; - -class PutImageStore : public MessageStore -{ - public: - - PutImageStore(StaticCompressor *compressor); - - virtual ~PutImageStore(); - - virtual const char *name() const - { - return "PutImage"; - } - - virtual unsigned char opcode() const - { - return X_PutImage; - } - - virtual unsigned int storage() const - { - return sizeof(PutImageMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new PutImageMessage(); - } - - virtual Message *create(const Message &message) const - { - return new PutImageMessage((const PutImageMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (PutImageMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PutImage_H */ diff --git a/nxcomp/PutPackedImage.cpp b/nxcomp/PutPackedImage.cpp deleted file mode 100644 index 66506ebbe..000000000 --- a/nxcomp/PutPackedImage.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "PutPackedImage.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -PutPackedImageStore::PutPackedImageStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = PUTPACKEDIMAGE_ENABLE_CACHE; - enableData = PUTPACKEDIMAGE_ENABLE_DATA; - enableCompress = PUTPACKEDIMAGE_ENABLE_COMPRESS; - - dataLimit = PUTPACKEDIMAGE_DATA_LIMIT; - dataOffset = PUTPACKEDIMAGE_DATA_OFFSET; - - cacheSlots = PUTPACKEDIMAGE_CACHE_SLOTS; - cacheThreshold = PUTPACKEDIMAGE_CACHE_THRESHOLD; - cacheLowerThreshold = PUTPACKEDIMAGE_CACHE_LOWER_THRESHOLD; - - // Since ProtoStep8 (#issue 108) - enableSplit = PUTPACKEDIMAGE_ENABLE_SPLIT_IF_PROTO_STEP_8; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -PutPackedImageStore::~PutPackedImageStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int PutPackedImageStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; - #endif - - // Client. - encodeBuffer.encodeCachedValue(*(buffer + 1), 8, - clientCache -> resourceCache); - - // Size. - encodeBuffer.encodeValue(GetUINT(buffer + 2, bigEndian), 16, 10); - - // Drawable. - encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> drawableCache); - // GC. - encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), - clientCache -> gcCache); - // Method. - encodeBuffer.encodeCachedValue(*(buffer + 12), 8, - clientCache -> methodCache); - // Format. - encodeBuffer.encodeValue(*(buffer + 13), 2); - - // SrcDepth. - encodeBuffer.encodeCachedValue(*(buffer + 14), 8, - clientCache -> depthCache); - // DstDepth. - encodeBuffer.encodeCachedValue(*(buffer + 15), 8, - clientCache -> depthCache); - // SrcLength. - encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 24, - clientCache -> putPackedImageSrcLengthCache); - // DstLength. - encodeBuffer.encodeCachedValue(GetULONG(buffer + 20, bigEndian), 24, - clientCache -> putPackedImageDstLengthCache); - // SrcX. - unsigned int x = GetUINT(buffer + 24, bigEndian); - int xDiff = x - clientCache -> putImageLastX; - clientCache -> putImageLastX = x; - encodeBuffer.encodeCachedValue(xDiff, 16, - clientCache -> putImageXCache, 8); - // SrcY. - unsigned int y = GetUINT(buffer + 26, bigEndian); - int yDiff = y - clientCache -> putImageLastY; - clientCache -> putImageLastY = y; - encodeBuffer.encodeCachedValue(yDiff, 16, - clientCache -> putImageYCache, 8); - // SrcWidth. - encodeBuffer.encodeCachedValue(GetUINT(buffer + 28, bigEndian), 16, - clientCache -> putImageWidthCache, 8); - // SrcHeight. - encodeBuffer.encodeCachedValue(GetUINT(buffer + 30, bigEndian), 16, - clientCache -> putImageHeightCache, 8); - // DstX. - x = GetUINT(buffer + 32, bigEndian); - xDiff = x - clientCache -> putImageLastX; - clientCache -> putImageLastX = x; - encodeBuffer.encodeCachedValue(xDiff, 16, - clientCache -> putImageXCache, 8); - // DstY. - y = GetUINT(buffer + 34, bigEndian); - yDiff = y - clientCache -> putImageLastY; - clientCache -> putImageLastY = y; - encodeBuffer.encodeCachedValue(yDiff, 16, - clientCache -> putImageYCache, 8); - // DstWidth. - encodeBuffer.encodeCachedValue(GetUINT(buffer + 36, bigEndian), 16, - clientCache -> putImageWidthCache, 8); - // DstHeight. - encodeBuffer.encodeCachedValue(GetUINT(buffer + 38, bigEndian), 16, - clientCache -> putImageHeightCache, 8); - - #ifdef DEBUG - *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int PutPackedImageStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; - #endif - - unsigned int value; - unsigned char cValue; - - // Client. - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> resourceCache); - - // Size. - decodeBuffer.decodeValue(size, 16, 10); - - size <<= 2; - - buffer = writeBuffer -> addMessage(size); - - *(buffer + 1) = cValue; - - // Drawable. - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - PutULONG(value, buffer + 4, bigEndian); - - // GC. - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - PutULONG(value, buffer + 8, bigEndian); - - // Method. - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> methodCache); - *(buffer + 12) = cValue; - - // Format. - decodeBuffer.decodeValue(value, 2); - *(buffer + 13) = value; - - // SrcDepth. - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - *(buffer + 14) = cValue; - - // DstDepth. - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - *(buffer + 15) = cValue; - - // SrcLength. - decodeBuffer.decodeCachedValue(value, 24, - clientCache -> putPackedImageSrcLengthCache); - PutULONG(value, buffer + 16, bigEndian); - - // DstLength. - decodeBuffer.decodeCachedValue(value, 24, - clientCache -> putPackedImageDstLengthCache); - PutULONG(value, buffer + 20, bigEndian); - - // SrcX. - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageXCache, 8); - clientCache -> putImageLastX += value; - clientCache -> putImageLastX &= 0xffff; - PutUINT(clientCache -> putImageLastX, buffer + 24, bigEndian); - - // SrcY. - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageYCache, 8); - clientCache -> putImageLastY += value; - clientCache -> putImageLastY &= 0xffff; - PutUINT(clientCache -> putImageLastY, buffer + 26, bigEndian); - - // SrcWidth. - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageWidthCache, 8); - PutUINT(value, buffer + 28, bigEndian); - - // SrcHeight. - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageHeightCache, 8); - PutUINT(value, buffer + 30, bigEndian); - - // DstX. - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageXCache, 8); - clientCache -> putImageLastX += value; - clientCache -> putImageLastX &= 0xffff; - PutUINT(clientCache -> putImageLastX, buffer + 32, bigEndian); - - // DstY. - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageYCache, 8); - clientCache -> putImageLastY += value; - clientCache -> putImageLastY &= 0xffff; - PutUINT(clientCache -> putImageLastY, buffer + 34, bigEndian); - - // DstWidth. - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageWidthCache, 8); - PutUINT(value, buffer + 36, bigEndian); - - // DstHeight. - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageHeightCache, 8); - PutUINT(value, buffer + 38, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int PutPackedImageStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; - - // - // Here is the fingerprint. - // - - putPackedImage -> client = *(buffer + 1); - - putPackedImage -> drawable = GetULONG(buffer + 4, bigEndian); - putPackedImage -> gcontext = GetULONG(buffer + 8, bigEndian); - - putPackedImage -> method = *(buffer + 12); - - putPackedImage -> format = *(buffer + 13); - putPackedImage -> src_depth = *(buffer + 14); - putPackedImage -> dst_depth = *(buffer + 15); - - putPackedImage -> src_length = GetULONG(buffer + 16, bigEndian); - putPackedImage -> dst_length = GetULONG(buffer + 20, bigEndian); - - putPackedImage -> src_x = GetUINT(buffer + 24, bigEndian); - putPackedImage -> src_y = GetUINT(buffer + 26, bigEndian); - putPackedImage -> src_width = GetUINT(buffer + 28, bigEndian); - putPackedImage -> src_height = GetUINT(buffer + 30, bigEndian); - - putPackedImage -> dst_x = GetUINT(buffer + 32, bigEndian); - putPackedImage -> dst_y = GetUINT(buffer + 34, bigEndian); - putPackedImage -> dst_width = GetUINT(buffer + 36, bigEndian); - putPackedImage -> dst_height = GetUINT(buffer + 38, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int PutPackedImageStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = putPackedImage -> client; - - PutULONG(putPackedImage -> drawable, buffer + 4, bigEndian); - PutULONG(putPackedImage -> gcontext, buffer + 8, bigEndian); - - *(buffer + 12) = putPackedImage -> method; - - *(buffer + 13) = putPackedImage -> format; - *(buffer + 14) = putPackedImage -> src_depth; - *(buffer + 15) = putPackedImage -> dst_depth; - - PutULONG(putPackedImage -> src_length, buffer + 16, bigEndian); - PutULONG(putPackedImage -> dst_length, buffer + 20, bigEndian); - - PutUINT(putPackedImage -> src_x, buffer + 24, bigEndian); - PutUINT(putPackedImage -> src_y, buffer + 26, bigEndian); - PutUINT(putPackedImage -> src_width, buffer + 28, bigEndian); - PutUINT(putPackedImage -> src_height, buffer + 30, bigEndian); - - PutUINT(putPackedImage -> dst_x, buffer + 32, bigEndian); - PutUINT(putPackedImage -> dst_y, buffer + 34, bigEndian); - PutUINT(putPackedImage -> dst_width, buffer + 36, bigEndian); - PutUINT(putPackedImage -> dst_height, buffer + 38, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void PutPackedImageStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; - - *logofs << name() << ": Identity format " - - << "drawable " << putPackedImage -> drawable << ", " - << "gcontext " << putPackedImage -> gcontext << ", " - - << "format " << (unsigned int) putPackedImage -> format << ", " - << "method " << (unsigned int) putPackedImage -> method << ", " - - << "src_depth " << (unsigned int) putPackedImage -> src_depth << ", " - << "dst_depth " << (unsigned int) putPackedImage -> dst_depth << ", " - - << "src_length " << putPackedImage -> src_length << ", " - << "dst_length " << putPackedImage -> dst_length << ", " - - << "src_x " << putPackedImage -> src_x << ", " - << "src_y " << putPackedImage -> src_y << ", " - << "src_width " << putPackedImage -> src_width << ", " - << "src_height " << putPackedImage -> src_height << ", " - - << "dst_x " << putPackedImage -> dst_x << ", " - << "dst_y " << putPackedImage -> dst_y << ", " - << "dst_width " << putPackedImage -> dst_width << ", " - << "dst_height " << putPackedImage -> dst_height << ", " - - << "size " << putPackedImage -> size_ << ".\n" - << logofs_flush; - - #endif -} - -void PutPackedImageStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Fields method, format, src_depth, dst_depth, - // src_length, dst_length, src_x, src_y, src_width, - // src_height. - // - // - // TODO: We should better investigate the effect of - // having fields src_x and src_y in identity instead - // of keeping them in differences. - // - - md5_append(md5_state_, buffer + 12, 20); -} - -void PutPackedImageStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - // - // Encode the variant part. - // - - PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; - PutPackedImageMessage *cachedPutPackedImage = (PutPackedImageMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " - << (unsigned int) putPackedImage -> client - << " as client field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(putPackedImage -> client, 8, - clientCache -> resourceCache); - - cachedPutPackedImage -> client = putPackedImage -> client; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putPackedImage -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(putPackedImage -> drawable, clientCache -> drawableCache); - - cachedPutPackedImage -> drawable = putPackedImage -> drawable; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putPackedImage -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(putPackedImage -> gcontext, clientCache -> gcCache); - - cachedPutPackedImage -> gcontext = putPackedImage -> gcontext; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putPackedImage -> dst_x - << " as " << "dst_x" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_x = putPackedImage -> dst_x - cachedPutPackedImage -> dst_x; - - encodeBuffer.encodeCachedValue(diff_x, 16, - clientCache -> putImageXCache, 8); - - cachedPutPackedImage -> dst_x = putPackedImage -> dst_x; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putPackedImage -> dst_y - << " as " << "dst_y" << " field.\n" << logofs_flush; - #endif - - unsigned short int diff_y = putPackedImage -> dst_y - cachedPutPackedImage -> dst_y; - - encodeBuffer.encodeCachedValue(diff_y, 16, - clientCache -> putImageYCache, 8); - - cachedPutPackedImage -> dst_y = putPackedImage -> dst_y; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putPackedImage -> dst_width - << " as " << "dst_width" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(putPackedImage -> dst_width, 16, - clientCache -> putImageWidthCache, 8); - - cachedPutPackedImage -> dst_width = putPackedImage -> dst_width; - - #ifdef TEST - *logofs << name() << ": Encoding value " << putPackedImage -> dst_height - << " as " << "dst_height" << " field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(putPackedImage -> dst_height, 16, - clientCache -> putImageHeightCache, 8); - - cachedPutPackedImage -> dst_height = putPackedImage -> dst_height; -} - -void PutPackedImageStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - // - // Decode the variant part. - // - - PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeCachedValue(putPackedImage -> client, 8, - clientCache -> resourceCache); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " - << (unsigned int) putPackedImage -> client - << " as client field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); - - putPackedImage -> drawable = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putPackedImage -> drawable - << " as drawable field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - putPackedImage -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putPackedImage -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageXCache, 8); - - putPackedImage -> dst_x += value; - putPackedImage -> dst_x &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putPackedImage -> dst_x - << " as dst_x field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageYCache, 8); - - putPackedImage -> dst_y += value; - putPackedImage -> dst_y &= 0xffff; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putPackedImage -> dst_y - << " as dst_y field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageWidthCache, 8); - - putPackedImage -> dst_width = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putPackedImage -> dst_width - << " as dst_width field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> putImageHeightCache, 8); - - putPackedImage -> dst_height = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << putPackedImage -> dst_height - << " as dst_height field.\n" << logofs_flush; - #endif -} - diff --git a/nxcomp/PutPackedImage.h b/nxcomp/PutPackedImage.h deleted file mode 100644 index d28ad39eb..000000000 --- a/nxcomp/PutPackedImage.h +++ /dev/null @@ -1,218 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef PutPackedImage_H -#define PutPackedImage_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define PUTPACKEDIMAGE_ENABLE_CACHE 1 -#define PUTPACKEDIMAGE_ENABLE_DATA 1 -#define PUTPACKEDIMAGE_ENABLE_COMPRESS 0 - -// -// We can't exceed lenght of 262144 bytes. -// - -#define PUTPACKEDIMAGE_DATA_LIMIT 262144 - 40 -#define PUTPACKEDIMAGE_DATA_OFFSET 40 - -#define PUTPACKEDIMAGE_CACHE_SLOTS 6000 -#define PUTPACKEDIMAGE_CACHE_THRESHOLD 70 -#define PUTPACKEDIMAGE_CACHE_LOWER_THRESHOLD 50 - -#define PUTPACKEDIMAGE_CACHE_THRESHOLD_IF_PACKED_SHADOW 97 -#define PUTPACKEDIMAGE_CACHE_LOWER_THRESHOLD_IF_PACKED_SHADOW 90 - -#define PUTPACKEDIMAGE_ENABLE_SPLIT_IF_PROTO_STEP_8 0 - -// -// The message class. -// - -class PutPackedImageMessage : public Message -{ - friend class PutPackedImageStore; - - public: - - PutPackedImageMessage() - { - } - - ~PutPackedImageMessage() - { - } - - // - // Here are the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char client; - - unsigned int drawable; - unsigned int gcontext; - - unsigned char format; - unsigned char method; - - unsigned char src_depth; - unsigned char dst_depth; - - unsigned int src_length; - unsigned int dst_length; - - short int src_x; - short int src_y; - unsigned short src_width; - unsigned short src_height; - - short int dst_x; - short int dst_y; - unsigned short dst_width; - unsigned short dst_height; -}; - -class PutPackedImageStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - PutPackedImageStore(StaticCompressor *compressor); - - virtual ~PutPackedImageStore(); - - virtual const char *name() const - { - return "PutPackedImage"; - } - - virtual unsigned char opcode() const - { - return X_NXPutPackedImage; - } - - virtual unsigned int storage() const - { - return sizeof(PutPackedImageMessage); - } - - // - // Very special of this class. - // - - int getPackedSize(const int position) const - { - PutPackedImageMessage *message = (PutPackedImageMessage *) (*messages_)[position]; - - if (message == NULL) - { - return 0; - } - - return dataOffset + message -> src_length; - } - - int getUnpackedSize(const int position) const - { - PutPackedImageMessage *message = (PutPackedImageMessage *) (*messages_)[position]; - - if (message == NULL) - { - return 0; - } - - return dataOffset + message -> dst_length; - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new PutPackedImageMessage(); - } - - virtual Message *create(const Message &message) const - { - return new PutPackedImageMessage((const PutPackedImageMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (PutPackedImageMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* PutPackedImage_H */ diff --git a/nxcomp/QueryFontReply.cpp b/nxcomp/QueryFontReply.cpp deleted file mode 100644 index ffd5eaee9..000000000 --- a/nxcomp/QueryFontReply.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "QueryFontReply.h" - -#include "ServerCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -QueryFontReplyStore::QueryFontReplyStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = QUERYFONTREPLY_ENABLE_CACHE; - enableData = QUERYFONTREPLY_ENABLE_DATA; - enableSplit = QUERYFONTREPLY_ENABLE_SPLIT; - - // Since ProtoStep7 (#issue 108) - enableCompress = QUERYFONTREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = QUERYFONTREPLY_DATA_LIMIT; - dataOffset = QUERYFONTREPLY_DATA_OFFSET; - - cacheSlots = QUERYFONTREPLY_CACHE_SLOTS; - cacheThreshold = QUERYFONTREPLY_CACHE_THRESHOLD; - cacheLowerThreshold = QUERYFONTREPLY_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -QueryFontReplyStore::~QueryFontReplyStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int QueryFontReplyStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Clear the padding bytes. - // - - unsigned char *pad = (unsigned char *) buffer; - - if (size >= 24) - { - PutULONG(0, pad + 20, bigEndian); - } - - if (size >= 40) - { - PutULONG(0, pad + 36, bigEndian); - } - - // - // TODO: This doesn't work. Probably these - // padding bytes are not padding anymore. - // This is to be investigated. - // - // pad += 60; - // - // while (pad + 16 <= (buffer + size)) - // { - // PutULONG(0, pad + 12, bigEndian); - // - // pad += 16; - // } - // - - #ifdef DEBUG - *logofs << name() << ": Cleaned padding bytes of " - << "message at " << message << ".\n" - << logofs_flush; - #endif - - return 1; -} - -int QueryFontReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - return 1; -} - -void QueryFontReplyStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - QueryFontReplyMessage *queryFontReply = (QueryFontReplyMessage *) message; - - *logofs << name() << ": Identity size " << queryFontReply -> size_ << ".\n"; - - #endif -} - -void QueryFontReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -} diff --git a/nxcomp/QueryFontReply.h b/nxcomp/QueryFontReply.h deleted file mode 100644 index e12fe4e4b..000000000 --- a/nxcomp/QueryFontReply.h +++ /dev/null @@ -1,136 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef QueryFontReply_H -#define QueryFontReply_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// -#define QUERYFONTREPLY_ENABLE_CACHE 1 -#define QUERYFONTREPLY_ENABLE_DATA 1 -#define QUERYFONTREPLY_ENABLE_SPLIT 0 - -#define QUERYFONTREPLY_DATA_LIMIT 1048576 - 32 -#define QUERYFONTREPLY_DATA_OFFSET 8 - -#define QUERYFONTREPLY_CACHE_SLOTS 200 -#define QUERYFONTREPLY_CACHE_THRESHOLD 20 -#define QUERYFONTREPLY_CACHE_LOWER_THRESHOLD 5 - -#define QUERYFONTREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -// -// The message class. -// - -class QueryFontReplyMessage : public Message -{ - friend class QueryFontReplyStore; - - public: - - QueryFontReplyMessage() - { - } - - ~QueryFontReplyMessage() - { - } -}; - -class QueryFontReplyStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - QueryFontReplyStore(StaticCompressor *compressor); - - virtual ~QueryFontReplyStore(); - - virtual const char *name() const - { - return "QueryFontReply"; - } - - virtual unsigned char opcode() const - { - return X_QueryFont; - } - - virtual unsigned int storage() const - { - return sizeof(QueryFontReplyMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new QueryFontReplyMessage(); - } - - virtual Message *create(const Message &message) const - { - return new QueryFontReplyMessage((const QueryFontReplyMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (QueryFontReplyMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* QueryFontReply_H */ diff --git a/nxcomp/ReadBuffer.cpp b/nxcomp/ReadBuffer.cpp deleted file mode 100644 index 1e2326cee..000000000 --- a/nxcomp/ReadBuffer.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ReadBuffer.h" - -#include "Transport.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -ReadBuffer::ReadBuffer(Transport *transport) - - : transport_(transport) -{ - // - // The read buffer will grow until - // reaching the maximum buffer size - // and then will remain stable at - // that size. - // - - initialReadSize_ = READ_BUFFER_DEFAULT_SIZE; - maximumBufferSize_ = READ_BUFFER_DEFAULT_SIZE; - - size_ = 0; - buffer_ = NULL; - - owner_ = 1; - length_ = 0; - start_ = 0; - - remaining_ = 0; -} - -ReadBuffer::~ReadBuffer() -{ - if (owner_ == 1) - { - delete [] buffer_; - } -} - -void ReadBuffer::readMessage(const unsigned char *message, unsigned int length) -{ - // - // To be here we must be the real owner - // of the buffer and there must not be - // pending bytes in the transport. - // - - #ifdef TEST - - if (owner_ == 0) - { - *logofs << "ReadBuffer: PANIC! Class for FD#" - << transport_ -> fd() << " doesn't " - << "appear to be the owner of the buffer " - << "while borrowing from the caller.\n" - << logofs_flush; - - HandleCleanup(); - } - - #endif - - // - // Be sure that any outstanding data from - // the transport is appended to our own - // byffer. - // - - if (transport_ -> pending() != 0) - { - #ifdef WARNING - *logofs << "ReadBuffer: WARNING! Class for FD#" - << transport_ -> fd() << " has pending " - << "data in the transport while " - << "borrowing from the caller.\n" - << logofs_flush; - #endif - - readMessage(); - - if (owner_ == 0) - { - convertBuffer(); - } - } - - // - // Can't borrow the buffer if there is data - // from a partial message. In this case add - // the new data to the end of our buffer. - // - - if (length_ == 0) - { - #ifdef TEST - *logofs << "ReadBuffer: Borrowing " << length - << " bytes from the caller for FD#" - << transport_ -> fd() << " with " - << length_ << " bytes in the buffer.\n" - << logofs_flush; - #endif - - delete [] buffer_; - - buffer_ = (unsigned char *) message; - size_ = length; - - length_ = length; - - owner_ = 0; - start_ = 0; - } - else - { - #ifdef TEST - *logofs << "ReadBuffer: Appending " << length - << " bytes from the caller for FD#" - << transport_ -> fd() << " with " - << length_ << " bytes in the buffer.\n" - << logofs_flush; - #endif - - appendBuffer(message, length); - } -} - -int ReadBuffer::readMessage() -{ - int pendingLength = transport_ -> pending(); - - if (pendingLength > 0) - { - // - // Can't move the data in the borrowed buffer, - // so use the tansport buffer only if we don't - // have any partial message. This can happen - // with the proxy where we need to deflate the - // stream. - // - - if (length_ == 0) - { - unsigned char *newBuffer; - - length_ = transport_ -> getPending(newBuffer); - - if (newBuffer == NULL) - { - #ifdef PANIC - *logofs << "ReadBuffer: PANIC! Failed to borrow " - << length_ << " bytes of memory for buffer " - << "in context [A].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to borrow memory for " - << "read buffer in context [A].\n"; - - HandleCleanup(); - } - - delete [] buffer_; - - buffer_ = newBuffer; - size_ = length_; - - owner_ = 0; - start_ = 0; - - #ifdef TEST - *logofs << "ReadBuffer: Borrowed " << length_ - << " pending bytes for FD#" << transport_ -> - fd() << ".\n" << logofs_flush; - #endif - - return length_; - } - #ifdef TEST - else - { - *logofs << "ReadBuffer: WARNING! Cannot borrow " - << pendingLength << " bytes for FD#" - << transport_ -> fd() << " with " - << length_ << " bytes in the buffer.\n" - << logofs_flush; - } - #endif - } - - unsigned int readLength = suggestedLength(pendingLength); - - #ifdef DEBUG - *logofs << "ReadBuffer: Requested " << readLength - << " bytes for FD#" << transport_ -> fd() - << " with readable " << transport_ -> readable() - << " remaining " << remaining_ << " pending " - << transport_ -> pending() << ".\n" - << logofs_flush; - #endif - - if (readLength < initialReadSize_) - { - readLength = initialReadSize_; - } - - #ifdef DEBUG - *logofs << "ReadBuffer: Buffer size is " << size_ - << " length " << length_ << " and start " - << start_ << ".\n" << logofs_flush; - #endif - - // - // We can't use the transport buffer - // to read our own data in it. - // - - #ifdef TEST - - if (owner_ == 0) - { - *logofs << "ReadBuffer: PANIC! Class for FD#" - << transport_ -> fd() << " doesn't " - << "appear to be the owner of the buffer " - << "while reading.\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - // - // Be sure that we have enough space - // to store all the requested data. - // - - if (buffer_ == NULL || length_ + readLength > size_) - { - unsigned int newSize = length_ + readLength; - - #ifdef TEST - *logofs << "ReadBuffer: Resizing buffer for FD#" - << transport_ -> fd() << " in read from " - << size_ << " to " << newSize << " bytes.\n" - << logofs_flush; - #endif - - unsigned char *newBuffer = allocateBuffer(newSize); - - memcpy(newBuffer, buffer_ + start_, length_); - - delete [] buffer_; - - buffer_ = newBuffer; - size_ = newSize; - - transport_ -> pendingReset(); - - owner_ = 1; - } - else if (start_ != 0 && length_ != 0) - { - // - // If any bytes are left due to a partial - // message, shift them to the beginning - // of the buffer. - // - - #ifdef TEST - *logofs << "ReadBuffer: Moving " << length_ - << " bytes of data " << "at beginning of " - << "the buffer for FD#" << transport_ -> fd() - << ".\n" << logofs_flush; - #endif - - memmove(buffer_, buffer_ + start_, length_); - } - - start_ = 0; - - #ifdef DEBUG - *logofs << "ReadBuffer: Buffer size is now " << size_ - << " length is " << length_ << " and start is " - << start_ << ".\n" << logofs_flush; - #endif - - unsigned char *readData = buffer_ + length_; - - #ifdef DEBUG - *logofs << "ReadBuffer: Going to read " << readLength - << " bytes from FD#" << transport_ -> fd() << ".\n" - << logofs_flush; - #endif - - int bytesRead = transport_ -> read(readData, readLength); - - if (bytesRead > 0) - { - #ifdef TEST - *logofs << "ReadBuffer: Read " << bytesRead - << " bytes from FD#" << transport_ -> fd() - << ".\n" << logofs_flush; - #endif - - length_ += bytesRead; - } - else if (bytesRead < 0) - { - // - // Check if there is more data pending than the - // size of the provided buffer. After reading - // the requested amount, in fact, the transport - // may have decompressed the data and produced - // more input. This trick allows us to always - // borrow the buffer from the transport, even - // when the partial read would have prevented - // that. - // - - if (transport_ -> pending() > 0) - { - #ifdef TEST - *logofs << "ReadBuffer: WARNING! Trying to read some " - << "more with " << transport_ -> pending() - << " bytes pending for FD#" << transport_ -> - fd() << ".\n" << logofs_flush; - #endif - - return readMessage(); - } - - #ifdef TEST - *logofs << "ReadBuffer: Error detected reading " - << "from FD#" << transport_ -> fd() - << ".\n" << logofs_flush; - #endif - - return -1; - } - #ifdef TEST - else - { - *logofs << "ReadBuffer: No data read from FD#" - << transport_ -> fd() << " with remaining " - << remaining_ << ".\n" << logofs_flush; - } - #endif - - return bytesRead; -} - -const unsigned char *ReadBuffer::getMessage(unsigned int &controlLength, - unsigned int &dataLength) -{ - #ifdef TEST - - if (transport_ -> pending() > 0) - { - *logofs << "ReadBuffer: PANIC! The transport " - << "appears to have data pending.\n" - << logofs_flush; - - HandleCleanup(); - } - - #endif - - if (length_ == 0) - { - #ifdef DEBUG - *logofs << "ReadBuffer: No message can be located " - << "for FD#" << transport_ -> fd() << ".\n" - << logofs_flush; - #endif - - if (owner_ == 0) - { - buffer_ = NULL; - size_ = 0; - - transport_ -> pendingReset(); - - owner_ = 1; - start_ = 0; - } - - return NULL; - } - - unsigned int trailerLength; - - #ifdef DEBUG - *logofs << "ReadBuffer: Going to locate message with " - << "start at " << start_ << " and length " - << length_ << " for FD#" << transport_ -> fd() - << ".\n" << logofs_flush; - #endif - - int located = locateMessage(buffer_ + start_, buffer_ + start_ + length_, - controlLength, dataLength, trailerLength); - - if (located == 0) - { - // - // No more complete messages are in - // the buffer. - // - - #ifdef DEBUG - *logofs << "ReadBuffer: No message was located " - << "for FD#" << transport_ -> fd() - << ".\n" << logofs_flush; - #endif - - if (owner_ == 0) - { - // - // Must move the remaining bytes in - // our own buffer. - // - - convertBuffer(); - } - - return NULL; - } - else - { - const unsigned char *result = buffer_ + start_; - - if (dataLength > 0) - { - // - // Message contains data, so go to the - // first byte of payload. - // - - result += trailerLength; - - start_ += (dataLength + trailerLength); - length_ -= (dataLength + trailerLength); - } - else - { - // - // It is a control message. - // - - start_ += (controlLength + trailerLength); - length_ -= (controlLength + trailerLength); - } - - #ifdef DEBUG - *logofs << "ReadBuffer: Located message for FD#" - << transport_ -> fd() << " with control length " - << controlLength << " and data length " - << dataLength << ".\n" << logofs_flush; - #endif - - remaining_ = 0; - - return result; - } -} - -int ReadBuffer::setSize(int initialReadSize, int maximumBufferSize) -{ - initialReadSize_ = initialReadSize; - maximumBufferSize_ = maximumBufferSize; - - #ifdef TEST - *logofs << "ReadBuffer: WARNING! Set buffer parameters to " - << initialReadSize_ << "/" << maximumBufferSize_ - << " for object at "<< this << ".\n" - << logofs_flush; - #endif - - return 1; -} - -void ReadBuffer::fullReset() -{ - #ifdef TEST - - if (owner_ == 0) - { - *logofs << "ReadBuffer: PANIC! Class for FD#" - << transport_ -> fd() << " doesn't " - << "appear to be the owner of the buffer " - << "in reset.\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - if (length_ == 0 && size_ > maximumBufferSize_) - { - #ifdef TEST - *logofs << "ReadBuffer: Resizing buffer for FD#" - << transport_ -> fd() << " in reset from " - << size_ << " to " << maximumBufferSize_ - << " bytes.\n" << logofs_flush; - #endif - - delete [] buffer_; - - int newSize = maximumBufferSize_; - - unsigned char *newBuffer = allocateBuffer(newSize); - - buffer_ = newBuffer; - size_ = newSize; - - transport_ -> pendingReset(); - - owner_ = 1; - start_ = 0; - } -} - -unsigned char *ReadBuffer::allocateBuffer(unsigned int newSize) -{ - unsigned char *newBuffer = new unsigned char[newSize]; - - if (newBuffer == NULL) - { - #ifdef PANIC - *logofs << "ReadBuffer: PANIC! Can't allocate " - << newSize << " bytes of memory for buffer " - << "in context [B].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory for " - << "read buffer in context [B].\n"; - - HandleCleanup(); - } - - #ifdef VALGRIND - - memset(newBuffer, '\0', newSize); - - #endif - - return newBuffer; -} - -void ReadBuffer::appendBuffer(const unsigned char *message, unsigned int length) -{ - if (start_ + length_ + length > size_) - { - unsigned int newSize = length_ + length + initialReadSize_; - - #ifdef TEST - *logofs << "ReadBuffer: WARNING! Resizing buffer " - << "for FD#" << transport_ -> fd() - << " from " << size_ << " to " << newSize - << " bytes.\n" << logofs_flush; - #endif - - unsigned char *newBuffer = allocateBuffer(newSize); - - memcpy(newBuffer, buffer_ + start_, length_); - - delete [] buffer_; - - buffer_ = newBuffer; - size_ = newSize; - - start_ = 0; - } - - memcpy(buffer_ + start_ + length_, message, length); - - length_ += length; - - transport_ -> pendingReset(); - - owner_ = 1; -} - -void ReadBuffer::convertBuffer() -{ - unsigned int newSize = length_ + initialReadSize_; - - #ifdef TEST - *logofs << "ReadBuffer: WARNING! Converting " - << length_ << " bytes to own buffer " - << "for FD#" << transport_ -> fd() - << " with new size " << newSize - << " bytes.\n" << logofs_flush; - #endif - - unsigned char *newBuffer = allocateBuffer(newSize); - - memcpy(newBuffer, buffer_ + start_, length_); - - buffer_ = newBuffer; - size_ = newSize; - - transport_ -> pendingReset(); - - owner_ = 1; - start_ = 0; -} diff --git a/nxcomp/ReadBuffer.h b/nxcomp/ReadBuffer.h deleted file mode 100644 index a12bcc9b3..000000000 --- a/nxcomp/ReadBuffer.h +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ReadBuffer_H -#define ReadBuffer_H - -#include "Misc.h" -#include "Timestamp.h" -#include "Transport.h" - -#define READ_BUFFER_DEFAULT_SIZE 8192 - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -class ReadBuffer -{ - public: - - ReadBuffer(Transport *transport); - - virtual ~ReadBuffer(); - - int readMessage(); - - void readMessage(const unsigned char *message, unsigned int length); - - const unsigned char *getMessage(unsigned int &dataLength) - { - unsigned int controlLength; - - return getMessage(controlLength, dataLength); - } - - const unsigned char *getMessage(unsigned int &controlLength, unsigned int &dataLength); - - unsigned int getLength() const - { - return length_; - } - - unsigned int getRemaining() const - { - return remaining_; - } - - int setSize(int initialReadSize, int initialbufferSize); - - void fullReset(); - - // - // Check if there is a complete - // message in the buffer. - // - - int checkMessage() - { - if (length_ == 0) - { - return 0; - } - else - { - unsigned int controlLength; - unsigned int dataLength; - unsigned int trailerLength; - - return (locateMessage(buffer_ + start_, buffer_ + start_ + length_, - controlLength, dataLength, trailerLength)); - } - } - - protected: - - virtual unsigned int suggestedLength(unsigned int pendingLength) = 0; - - virtual int locateMessage(const unsigned char *start, - const unsigned char *end, - unsigned int &controlLength, - unsigned int &dataLength, - unsigned int &trailerLength) = 0; - - unsigned char *allocateBuffer(unsigned int newSize); - - void appendBuffer(const unsigned char *message, unsigned int length); - - void convertBuffer(); - - Transport *transport_; - - unsigned char *buffer_; - - unsigned int length_; - unsigned int size_; - unsigned int start_; - unsigned int remaining_; - - int owner_; - - unsigned int initialReadSize_; - unsigned int maximumBufferSize_; -}; - -#endif /* ReadBuffer_H */ diff --git a/nxcomp/RenderAddGlyphs.cpp b/nxcomp/RenderAddGlyphs.cpp deleted file mode 100644 index ed0864b93..000000000 --- a/nxcomp/RenderAddGlyphs.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderAddGlyphs.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - size = MESSAGE_OFFSET + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 4, bigEndian), 29, - clientCache -> renderGlyphSetCache); - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 8, bigEndian), 32, - clientCache -> renderNumGlyphsCache, 8); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeCachedValue(value, 29, - clientCache -> renderGlyphSetCache); - - PutULONG(value, buffer + 4, bigEndian); - - decodeBuffer.decodeCachedValue(value, 32, - clientCache -> renderNumGlyphsCache, 8); - - PutULONG(value, buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.add_glyphs.type = *(buffer + 1); - - renderExtension -> data.add_glyphs.set_id = GetULONG(buffer + 4, bigEndian); - renderExtension -> data.add_glyphs.num_elm = GetULONG(buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.add_glyphs.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.add_glyphs.type; - - PutULONG(renderExtension -> data.add_glyphs.set_id, buffer + 4, bigEndian); - PutULONG(renderExtension -> data.add_glyphs.num_elm, buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.add_glyphs.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - md5_append(md5_state, buffer + 1, 3); - md5_append(md5_state, buffer + 8, 4); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(renderExtension -> data.add_glyphs.set_id, 29, - clientCache -> renderGlyphSetCache); - - cachedRenderExtension -> data.add_glyphs.set_id = - renderExtension -> data.add_glyphs.set_id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.add_glyphs.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(renderExtension -> data.add_glyphs.set_id, 29, - clientCache -> renderGlyphSetCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.add_glyphs.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderAddGlyphs.h b/nxcomp/RenderAddGlyphs.h deleted file mode 100644 index d3c8cd158..000000000 --- a/nxcomp/RenderAddGlyphs.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderAddGlyphs_H -#define RenderAddGlyphs_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderAddGlyphs" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderAddGlyphsStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 12 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderAddGlyphs_H */ diff --git a/nxcomp/RenderChangePicture.cpp b/nxcomp/RenderChangePicture.cpp deleted file mode 100644 index 2abb97493..000000000 --- a/nxcomp/RenderChangePicture.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderChangePicture.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - size = MESSAGE_OFFSET + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> renderSrcPictureCache); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeXidValue(value, clientCache -> renderSrcPictureCache); - - PutULONG(value, buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - #ifdef DEBUG - - if (size == MESSAGE_OFFSET + 4) - { - *logofs << name() << ": Mask is " << GetULONG(buffer + 8, bigEndian) - << " value is " << GetULONG(buffer + 12, bigEndian) - << ".\n" << logofs_flush; - } - else - { - *logofs << name() << ": WARNING! Unexpected size. Mask is " - << GetULONG(buffer + 8, bigEndian) << ".\n" - << logofs_flush; - } - - #endif - - encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.change_picture.type = *(buffer + 1); - - renderExtension -> data.change_picture.src_id = GetULONG(buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.change_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.change_picture.type; - - PutULONG(renderExtension -> data.change_picture.src_id, buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.change_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - md5_append(md5_state, buffer + 1, 3); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(renderExtension -> data.change_picture.src_id, - clientCache -> renderSrcPictureCache); - - cachedRenderExtension -> data.change_picture.src_id = - renderExtension -> data.change_picture.src_id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.change_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(renderExtension -> data.change_picture.src_id, - clientCache -> renderSrcPictureCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.change_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderChangePicture.h b/nxcomp/RenderChangePicture.h deleted file mode 100644 index 4bab1ef98..000000000 --- a/nxcomp/RenderChangePicture.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderChangePicture_H -#define RenderChangePicture_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderChangePicture" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderChangePictureStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 8 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderChangePicture_H */ diff --git a/nxcomp/RenderComposite.cpp b/nxcomp/RenderComposite.cpp deleted file mode 100644 index e8603a7da..000000000 --- a/nxcomp/RenderComposite.cpp +++ /dev/null @@ -1,396 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderComposite.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), - clientCache -> renderSrcPictureCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 12, bigEndian), - clientCache -> renderMaskPictureCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 16, bigEndian), - clientCache -> renderDstPictureCache); - - // - // Src X and Y. - // - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 20, bigEndian), - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 22, bigEndian), - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - // - // Mask X and Y. - // - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 24, bigEndian), - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 26, bigEndian), - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - // - // Dst X and Y. - // - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 28, bigEndian), - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 30, bigEndian), - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - // - // Width and height. - // - - encodeBuffer.encodeCachedValue(GetUINT(buffer + 32, bigEndian), 16, - clientCache -> renderWidthCache, 11); - - encodeBuffer.encodeCachedValue(GetUINT(buffer + 34, bigEndian), 16, - clientCache -> renderHeightCache, 11); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - decodeBuffer.decodeXidValue(value, clientCache -> renderSrcPictureCache); - - PutULONG(value, buffer + 8, bigEndian); - - decodeBuffer.decodeXidValue(value, clientCache -> renderMaskPictureCache); - - PutULONG(value, buffer + 12, bigEndian); - - decodeBuffer.decodeXidValue(value, clientCache -> renderDstPictureCache); - - PutULONG(value, buffer + 16, bigEndian); - - // - // Src X and Y. - // - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - PutUINT(clientCache -> renderLastX, buffer + 20, bigEndian); - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - PutUINT(clientCache -> renderLastY, buffer + 22, bigEndian); - - // - // Mask X and Y. - // - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - PutUINT(clientCache -> renderLastX, buffer + 24, bigEndian); - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - PutUINT(clientCache -> renderLastY, buffer + 26, bigEndian); - - // - // Dst X and Y. - // - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - PutUINT(clientCache -> renderLastX, buffer + 28, bigEndian); - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - PutUINT(clientCache -> renderLastY, buffer + 30, bigEndian); - - // - // Width and height. - // - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> renderWidthCache, 11); - - PutUINT(value, buffer + 32, bigEndian); - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> renderHeightCache, 11); - - PutUINT(value, buffer + 34, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.composite.type = *(buffer + 1); - renderExtension -> data.composite.op = *(buffer + 4); - - renderExtension -> data.composite.src_id = GetULONG(buffer + 8, bigEndian); - renderExtension -> data.composite.msk_id = GetULONG(buffer + 12, bigEndian); - renderExtension -> data.composite.dst_id = GetULONG(buffer + 16, bigEndian); - - renderExtension -> data.composite.src_x = GetUINT(buffer + 20, bigEndian); - renderExtension -> data.composite.src_y = GetUINT(buffer + 22, bigEndian); - - renderExtension -> data.composite.msk_x = GetUINT(buffer + 24, bigEndian); - renderExtension -> data.composite.msk_y = GetUINT(buffer + 26, bigEndian); - - renderExtension -> data.composite.dst_x = GetUINT(buffer + 28, bigEndian); - renderExtension -> data.composite.dst_y = GetUINT(buffer + 30, bigEndian); - - renderExtension -> data.composite.width = GetUINT(buffer + 32, bigEndian); - renderExtension -> data.composite.height = GetUINT(buffer + 34, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.composite.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.composite.type; - *(buffer + 4) = renderExtension -> data.composite.op; - - PutULONG(renderExtension -> data.composite.src_id, buffer + 8, bigEndian); - PutULONG(renderExtension -> data.composite.msk_id, buffer + 12, bigEndian); - PutULONG(renderExtension -> data.composite.dst_id, buffer + 16, bigEndian); - - PutUINT(renderExtension -> data.composite.src_x, buffer + 20, bigEndian); - PutUINT(renderExtension -> data.composite.src_y, buffer + 22, bigEndian); - - PutUINT(renderExtension -> data.composite.msk_x, buffer + 24, bigEndian); - PutUINT(renderExtension -> data.composite.msk_y, buffer + 26, bigEndian); - - PutUINT(renderExtension -> data.composite.dst_x, buffer + 28, bigEndian); - PutUINT(renderExtension -> data.composite.dst_y, buffer + 30, bigEndian); - - PutUINT(renderExtension -> data.composite.width, buffer + 32, bigEndian); - PutUINT(renderExtension -> data.composite.height, buffer + 34, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.composite.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - // - // Include the minor opcode and size in the - // identity, plus the operator, the x and y - // of the source and mask and the width and - // height of the destination. - // - - md5_append(md5_state, buffer + 1, 4); - md5_append(md5_state, buffer + 20, 8); - md5_append(md5_state, buffer + 32, 4); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Source " << renderExtension -> data.composite.src_id - << " mask " << renderExtension -> data.composite.msk_id - << " destination " << renderExtension -> data.composite.msk_id - << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(renderExtension -> data.composite.src_id, - clientCache -> renderSrcPictureCache); - - cachedRenderExtension -> data.composite.src_id = - renderExtension -> data.composite.src_id; - - encodeBuffer.encodeXidValue(renderExtension -> data.composite.msk_id, - clientCache -> renderMaskPictureCache); - - cachedRenderExtension -> data.composite.msk_id = - renderExtension -> data.composite.msk_id; - - encodeBuffer.encodeXidValue(renderExtension -> data.composite.dst_id, - clientCache -> renderDstPictureCache); - - cachedRenderExtension -> data.composite.dst_id = - renderExtension -> data.composite.dst_id; - - // - // Dst X and Y. - // - - unsigned int value; - unsigned int previous; - - value = renderExtension -> data.composite.dst_x; - previous = cachedRenderExtension -> data.composite.dst_x; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderXCache, 11); - - cachedRenderExtension -> data.composite.dst_x = value; - - value = renderExtension -> data.composite.dst_y; - previous = cachedRenderExtension -> data.composite.dst_y; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderYCache, 11); - - cachedRenderExtension -> data.composite.dst_y = value; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.composite.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(renderExtension -> data.composite.src_id, - clientCache -> renderSrcPictureCache); - - decodeBuffer.decodeXidValue(renderExtension -> data.composite.msk_id, - clientCache -> renderMaskPictureCache); - - decodeBuffer.decodeXidValue(renderExtension -> data.composite.dst_id, - clientCache -> renderDstPictureCache); - - // - // Dst X and Y. - // - - unsigned int value; - unsigned int previous; - - previous = renderExtension -> data.composite.dst_x; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderXCache, 11); - - renderExtension -> data.composite.dst_x = value; - - previous = renderExtension -> data.composite.dst_y; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderYCache, 11); - - renderExtension -> data.composite.dst_y = value; - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.composite.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderComposite.h b/nxcomp/RenderComposite.h deleted file mode 100644 index aafa1e776..000000000 --- a/nxcomp/RenderComposite.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderComposite_H -#define RenderComposite_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderComposite" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderCompositeStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 36 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 0 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 0 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderComposite_H */ diff --git a/nxcomp/RenderCompositeGlyphs.cpp b/nxcomp/RenderCompositeGlyphs.cpp deleted file mode 100644 index 74b3ec779..000000000 --- a/nxcomp/RenderCompositeGlyphs.cpp +++ /dev/null @@ -1,625 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderCompositeGlyphs.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding value " - << ((size - MESSAGE_OFFSET) >> 2) << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << size - << ".\n" << logofs_flush; - #endif - - size = MESSAGE_OFFSET + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), - clientCache -> renderSrcPictureCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 12, bigEndian), - clientCache -> renderDstPictureCache); - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 32, - clientCache -> renderFormatCache); - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 20, bigEndian), 29, - clientCache -> renderGlyphSetCache); - - unsigned int src_x = GetUINT(buffer + 24, bigEndian); - unsigned int src_y = GetUINT(buffer + 26, bigEndian); - - // Since ProtoStep8 (#issue 108) - encodeBuffer.encodeDiffCachedValue(src_x, - clientCache -> renderGlyphX, 16, - clientCache -> renderGlyphXCache, 11); - - encodeBuffer.encodeDiffCachedValue(src_y, - clientCache -> renderGlyphY, 16, - clientCache -> renderGlyphYCache, 11); - - #ifdef TEST - *logofs << name() << ": Encoded source X " - << GetUINT(buffer + 24, bigEndian) << " source Y " - << GetUINT(buffer + 26, bigEndian) << ".\n" - << logofs_flush; - #endif - - // - // Bytes from 28 to 36 contain in the order: - // - // 1 byte for the length of the first string. - // 3 bytes of padding. - // 2 bytes for the X offset. - // 2 bytes for the Y offset. - // - // Encode these bytes differentially to match - // all the strings that have equal glyphs. - // - // Only manage the first string of glyphs. The - // others strings should match, if they contain - // the same glyphs, since the offset are rela- - // tive to the first offset coordinates. - // - - // Since ProtoStep8 (#issue 108) - if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) - { - unsigned int numGlyphs = *(buffer + 28); - - encodeBuffer.encodeCachedValue(numGlyphs, 8, - clientCache -> renderNumGlyphsCache); - - unsigned int offset_x = GetUINT(buffer + 32, bigEndian); - unsigned int offset_y = GetUINT(buffer + 34, bigEndian); - - if (offset_x == src_x && offset_y == src_y) - { - encodeBuffer.encodeBoolValue(0); - - #ifdef TEST - *logofs << name() << ": Matched offset X " - << GetUINT(buffer + 32, bigEndian) << " offset Y " - << GetUINT(buffer + 34, bigEndian) << ".\n" - << logofs_flush; - #endif - } - else - { - encodeBuffer.encodeBoolValue(1); - - encodeBuffer.encodeDiffCachedValue(offset_x, - clientCache -> renderGlyphX, 16, - clientCache -> renderGlyphXCache, 11); - - encodeBuffer.encodeDiffCachedValue(offset_y, - clientCache -> renderGlyphY, 16, - clientCache -> renderGlyphYCache, 11); - - #ifdef TEST - *logofs << name() << ": Missed offset X " - << GetUINT(buffer + 32, bigEndian) << " offset Y " - << GetUINT(buffer + 34, bigEndian) << ".\n" - << logofs_flush; - #endif - } - } - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - decodeBuffer.decodeXidValue(value, - clientCache -> renderSrcPictureCache); - - PutULONG(value, buffer + 8, bigEndian); - - decodeBuffer.decodeXidValue(value, - clientCache -> renderDstPictureCache); - - PutULONG(value, buffer + 12, bigEndian); - - decodeBuffer.decodeCachedValue(value, 32, - clientCache -> renderFormatCache); - - PutULONG(value, buffer + 16, bigEndian); - - decodeBuffer.decodeCachedValue(value, 29, - clientCache -> renderGlyphSetCache); - - PutULONG(value, buffer + 20, bigEndian); - - unsigned int src_x; - unsigned int src_y; - - // Since ProtoStep8 (#issue 108) - decodeBuffer.decodeDiffCachedValue(src_x, - clientCache -> renderGlyphX, 16, - clientCache -> renderGlyphXCache, 11); - - decodeBuffer.decodeDiffCachedValue(src_y, - clientCache -> renderGlyphY, 16, - clientCache -> renderGlyphYCache, 11); - - PutUINT(src_x, buffer + 24, bigEndian); - PutUINT(src_y, buffer + 26, bigEndian); - - // Since ProtoStep8 (#issue 108) - if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) - { - decodeBuffer.decodeCachedValue(value, 8, - clientCache -> renderNumGlyphsCache); - - *(buffer + 28) = value; - - decodeBuffer.decodeBoolValue(value); - - if (value == 0) - { - PutUINT(src_x, buffer + 32, bigEndian); - PutUINT(src_y, buffer + 34, bigEndian); - } - else - { - decodeBuffer.decodeDiffCachedValue(src_x, - clientCache -> renderGlyphX, 16, - clientCache -> renderGlyphXCache, 11); - - PutUINT(src_x, buffer + 32, bigEndian); - - decodeBuffer.decodeDiffCachedValue(src_y, - clientCache -> renderGlyphY, 16, - clientCache -> renderGlyphYCache, 11); - - PutUINT(src_y, buffer + 34, bigEndian); - } - } - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - // Since ProtoStep8 (#issue 108) - if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) - { - encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET_IF_PROTO_STEP_8, - size, bigEndian, channelCache); - } - else if (size > MESSAGE_OFFSET) - { - encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - } - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of text data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - // Since ProtoStep8 (#issue 108) - if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) - { - decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET_IF_PROTO_STEP_8, - size, bigEndian, channelCache); - } - else if (size > MESSAGE_OFFSET) - { - decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - } - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.composite_glyphs.type = *(buffer + 1); - renderExtension -> data.composite_glyphs.op = *(buffer + 4); - - renderExtension -> data.composite_glyphs.src_id = GetULONG(buffer + 8, bigEndian); - renderExtension -> data.composite_glyphs.dst_id = GetULONG(buffer + 12, bigEndian); - - renderExtension -> data.composite_glyphs.format = GetULONG(buffer + 16, bigEndian); - renderExtension -> data.composite_glyphs.set_id = GetULONG(buffer + 20, bigEndian); - - renderExtension -> data.composite_glyphs.src_x = GetUINT(buffer + 24, bigEndian); - renderExtension -> data.composite_glyphs.src_y = GetUINT(buffer + 26, bigEndian); - - // Since ProtoStep8 (#issue 108) - if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) - { - renderExtension -> data.composite_glyphs.num_elm = *(buffer + 28); - - renderExtension -> data.composite_glyphs.offset_x = GetUINT(buffer + 32, bigEndian); - renderExtension -> data.composite_glyphs.offset_y = GetUINT(buffer + 34, bigEndian); - } - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.composite_glyphs.type - << " size is " << renderExtension -> size_ << " identity size " - << renderExtension -> i_size_ << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.composite_glyphs.type; - *(buffer + 4) = renderExtension -> data.composite_glyphs.op; - - PutULONG(renderExtension -> data.composite_glyphs.src_id, buffer + 8, bigEndian); - PutULONG(renderExtension -> data.composite_glyphs.dst_id, buffer + 12, bigEndian); - - PutULONG(renderExtension -> data.composite_glyphs.format, buffer + 16, bigEndian); - PutULONG(renderExtension -> data.composite_glyphs.set_id, buffer + 20, bigEndian); - - PutUINT(renderExtension -> data.composite_glyphs.src_x, buffer + 24, bigEndian); - PutUINT(renderExtension -> data.composite_glyphs.src_y, buffer + 26, bigEndian); - - // Since ProtoStep8 (#issue 108) - if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) - { - *(buffer + 28) = renderExtension -> data.composite_glyphs.num_elm; - - PutUINT(renderExtension -> data.composite_glyphs.offset_x, buffer + 32, bigEndian); - PutUINT(renderExtension -> data.composite_glyphs.offset_y, buffer + 34, bigEndian); - } - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.composite_glyphs.type - << " size is " << renderExtension -> size_ << " identity size " - << renderExtension -> i_size_ << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - // - // Include minor opcode, size and - // the composite operator in the - // identity. - // - - md5_append(md5_state, buffer + 1, 4); - - // - // Include the format. - // - - md5_append(md5_state, buffer + 16, 4); - - // - // Also include the length of the - // first string. - // - - // Since ProtoStep8 (#issue 108) - if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) - { - md5_append(md5_state, buffer + 28, 1); - } -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(renderExtension -> data.composite_glyphs.src_id, - clientCache -> renderSrcPictureCache); - - cachedRenderExtension -> data.composite_glyphs.src_id = - renderExtension -> data.composite_glyphs.src_id; - - encodeBuffer.encodeXidValue(renderExtension -> data.composite_glyphs.dst_id, - clientCache -> renderDstPictureCache); - - cachedRenderExtension -> data.composite_glyphs.dst_id = - renderExtension -> data.composite_glyphs.dst_id; - - encodeBuffer.encodeCachedValue(renderExtension -> data.composite_glyphs.set_id, 29, - clientCache -> renderGlyphSetCache); - - cachedRenderExtension -> data.composite_glyphs.set_id = - renderExtension -> data.composite_glyphs.set_id; - - // - // Src X and Y. - // - // The source X and Y coordinates are - // encoded as differerences in respect - // to the cached message. - // - - unsigned int value; - unsigned int previous; - - // Since ProtoStep8 (#issue 108) - value = renderExtension -> data.composite_glyphs.src_x; - previous = cachedRenderExtension -> data.composite_glyphs.src_x; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderGlyphXCache, 11); - - cachedRenderExtension -> data.composite_glyphs.src_x = value; - - value = renderExtension -> data.composite_glyphs.src_y; - previous = cachedRenderExtension -> data.composite_glyphs.src_y; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderGlyphYCache, 11); - - cachedRenderExtension -> data.composite_glyphs.src_y = value; - - #ifdef TEST - *logofs << name() << ": Encoded source X " - << renderExtension -> data.composite_glyphs.src_x << " source Y " - << renderExtension -> data.composite_glyphs.src_y << ".\n" - << logofs_flush; - #endif - - // Since ProtoStep8 (#issue 108) - if (renderExtension -> size_ >= MESSAGE_OFFSET_IF_PROTO_STEP_8) - { - // - // Offset X and Y. - // - - if (renderExtension -> data.composite_glyphs.offset_x == - renderExtension -> data.composite_glyphs.src_x && - renderExtension -> data.composite_glyphs.offset_y == - renderExtension -> data.composite_glyphs.src_y) - { - encodeBuffer.encodeBoolValue(0); - - cachedRenderExtension -> data.composite_glyphs.offset_x = - renderExtension -> data.composite_glyphs.offset_x; - - cachedRenderExtension -> data.composite_glyphs.offset_y = - renderExtension -> data.composite_glyphs.offset_y; - - #ifdef TEST - *logofs << name() << ": Matched offset X " - << renderExtension -> data.composite_glyphs.offset_x << " offset Y " - << renderExtension -> data.composite_glyphs.offset_y << ".\n" - << logofs_flush; - #endif - } - else - { - encodeBuffer.encodeBoolValue(1); - - value = renderExtension -> data.composite_glyphs.offset_x; - previous = cachedRenderExtension -> data.composite_glyphs.offset_x; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderGlyphXCache, 11); - - cachedRenderExtension -> data.composite_glyphs.offset_x = value; - - value = renderExtension -> data.composite_glyphs.offset_y; - previous = cachedRenderExtension -> data.composite_glyphs.offset_y; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderGlyphYCache, 11); - - cachedRenderExtension -> data.composite_glyphs.offset_y = value; - - #ifdef TEST - *logofs << name() << ": Missed offset X " - << renderExtension -> data.composite_glyphs.offset_x << " offset Y " - << renderExtension -> data.composite_glyphs.offset_y << ".\n" - << logofs_flush; - #endif - } - } - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.composite_glyphs.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(renderExtension -> data.composite_glyphs.src_id, - clientCache -> renderSrcPictureCache); - - decodeBuffer.decodeXidValue(renderExtension -> data.composite_glyphs.dst_id, - clientCache -> renderDstPictureCache); - - decodeBuffer.decodeCachedValue(renderExtension -> data.composite_glyphs.set_id, 29, - clientCache -> renderGlyphSetCache); - - // - // Src X and Y. - // - - unsigned int value; - unsigned int previous; - - // Since ProtoStep8 (#issue 108) - previous = renderExtension -> data.composite_glyphs.src_x; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderGlyphXCache, 11); - - renderExtension -> data.composite_glyphs.src_x = value; - - previous = renderExtension -> data.composite_glyphs.src_y; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderGlyphYCache, 11); - - renderExtension -> data.composite_glyphs.src_y = value; - - // Since ProtoStep8 (#issue 108) - if (renderExtension -> size_ >= MESSAGE_OFFSET_IF_PROTO_STEP_8) - { - // - // Offset X and Y. - // - - decodeBuffer.decodeBoolValue(value); - - if (value == 0) - { - renderExtension -> data.composite_glyphs.offset_x = - renderExtension -> data.composite_glyphs.src_x; - - renderExtension -> data.composite_glyphs.offset_y = - renderExtension -> data.composite_glyphs.src_y; - } - else - { - previous = renderExtension -> data.composite_glyphs.offset_x; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderGlyphXCache, 11); - - renderExtension -> data.composite_glyphs.offset_x = value; - - previous = renderExtension -> data.composite_glyphs.offset_y; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderGlyphYCache, 11); - - renderExtension -> data.composite_glyphs.offset_y = value; - } - } - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.composite_glyphs.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderCompositeGlyphs.h b/nxcomp/RenderCompositeGlyphs.h deleted file mode 100644 index 1062ee781..000000000 --- a/nxcomp/RenderCompositeGlyphs.h +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderCompositeGlyphs_H -#define RenderCompositeGlyphs_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderCompositeGlyphs" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderCompositeGlyphsStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 28 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Encode the first 8 bytes of the -// data differentially in newer -// protocol versions. -// - -#undef MESSAGE_OFFSET_IF_PROTO_STEP_8 -#define MESSAGE_OFFSET_IF_PROTO_STEP_8 36 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - // Since ProtoStep8 (#issue 108) - unsigned int offset = MESSAGE_OFFSET_IF_PROTO_STEP_8; - - return (size >= offset ? offset : size); - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderCompositeGlyphs_H */ diff --git a/nxcomp/RenderCreateGlyphSet.cpp b/nxcomp/RenderCreateGlyphSet.cpp deleted file mode 100644 index 3e7a71721..000000000 --- a/nxcomp/RenderCreateGlyphSet.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderCreateGlyphSet.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeNewXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> renderGlyphSetCache, - clientCache -> renderFreeGlyphSetCache); - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 8, bigEndian), 32, - clientCache -> renderFormatCache); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeNewXidValue(value, - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> renderGlyphSetCache, - clientCache -> renderFreeGlyphSetCache); - - PutULONG(value, buffer + 4, bigEndian); - - decodeBuffer.decodeCachedValue(value, 32, - clientCache -> renderFormatCache); - - PutULONG(value, buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.create_set.type = *(buffer + 1); - - renderExtension -> data.create_set.set_id = GetULONG(buffer + 4, bigEndian); - renderExtension -> data.create_set.format = GetULONG(buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.create_set.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.create_set.type; - - PutULONG(renderExtension -> data.create_set.set_id, buffer + 4, bigEndian); - PutULONG(renderExtension -> data.create_set.format, buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.create_set.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - md5_append(md5_state, buffer + 1, 3); - md5_append(md5_state, buffer + 8, 4); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeNewXidValue(renderExtension -> data.create_set.set_id, - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> renderGlyphSetCache, - clientCache -> renderFreeGlyphSetCache); - - cachedRenderExtension -> data.create_set.set_id = - renderExtension -> data.create_set.set_id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.create_set.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeNewXidValue(renderExtension -> data.create_set.set_id, - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> renderGlyphSetCache, - clientCache -> renderFreeGlyphSetCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.create_set.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderCreateGlyphSet.h b/nxcomp/RenderCreateGlyphSet.h deleted file mode 100644 index 10f5d6699..000000000 --- a/nxcomp/RenderCreateGlyphSet.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderCreateGlyphSet_H -#define RenderCreateGlyphSet_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderCreateGlyphSet" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderCreateGlyphSetStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 12 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 0 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 0 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderCreateGlyphSet_H */ diff --git a/nxcomp/RenderCreatePicture.cpp b/nxcomp/RenderCreatePicture.cpp deleted file mode 100644 index 2fd736cbb..000000000 --- a/nxcomp/RenderCreatePicture.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderCreatePicture.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - size = MESSAGE_OFFSET + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeNewXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> renderSrcPictureCache, - clientCache -> renderFreePictureCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), - clientCache -> drawableCache); - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 12, bigEndian), 32, - clientCache -> renderFormatCache); - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 32, - clientCache -> renderValueMaskCache); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeNewXidValue(value, - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> renderSrcPictureCache, - clientCache -> renderFreePictureCache); - - PutULONG(value, buffer + 4, bigEndian); - - decodeBuffer.decodeXidValue(value, - clientCache -> drawableCache); - - PutULONG(value, buffer + 8, bigEndian); - - decodeBuffer.decodeCachedValue(value, 32, - clientCache -> renderFormatCache); - - PutULONG(value, buffer + 12, bigEndian); - - decodeBuffer.decodeCachedValue(value, 32, - clientCache -> renderValueMaskCache); - - PutULONG(value, buffer + 16, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.create_picture.type = *(buffer + 1); - - renderExtension -> data.create_picture.src_id = GetULONG(buffer + 4, bigEndian); - renderExtension -> data.create_picture.dst_id = GetULONG(buffer + 8, bigEndian); - - renderExtension -> data.create_picture.format = GetULONG(buffer + 12, bigEndian); - renderExtension -> data.create_picture.mask = GetULONG(buffer + 16, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.create_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.create_picture.type; - - PutULONG(renderExtension -> data.create_picture.src_id, buffer + 4, bigEndian); - PutULONG(renderExtension -> data.create_picture.dst_id, buffer + 8, bigEndian); - - PutULONG(renderExtension -> data.create_picture.format, buffer + 12, bigEndian); - PutULONG(renderExtension -> data.create_picture.mask, buffer + 16, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.create_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - md5_append(md5_state, buffer + 1, 3); - md5_append(md5_state, buffer + 12, 8); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding new id value " - << renderExtension -> data.create_picture.src_id - << ".\n"; - #endif - - encodeBuffer.encodeNewXidValue(renderExtension -> data.create_picture.src_id, - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> renderSrcPictureCache, - clientCache -> renderFreePictureCache); - - cachedRenderExtension -> data.create_picture.src_id = - renderExtension -> data.create_picture.src_id; - - encodeBuffer.encodeXidValue(renderExtension -> data.create_picture.dst_id, - clientCache -> drawableCache); - - cachedRenderExtension -> data.create_picture.dst_id = - renderExtension -> data.create_picture.dst_id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.create_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeNewXidValue(renderExtension -> data.create_picture.src_id, - clientCache -> lastId, clientCache -> lastIdCache, - clientCache -> renderSrcPictureCache, - clientCache -> renderFreePictureCache); - - decodeBuffer.decodeXidValue(renderExtension -> data.create_picture.dst_id, - clientCache -> drawableCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.create_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderCreatePicture.h b/nxcomp/RenderCreatePicture.h deleted file mode 100644 index ae2f583a0..000000000 --- a/nxcomp/RenderCreatePicture.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderCreatePicture_H -#define RenderCreatePicture_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderCreatePicture" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderCreatePictureStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 20 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderCreatePicture_H */ diff --git a/nxcomp/RenderExtension.cpp b/nxcomp/RenderExtension.cpp deleted file mode 100644 index bd2285e82..000000000 --- a/nxcomp/RenderExtension.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "NXrender.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -#include "RenderExtension.h" - -#include "RenderGenericRequest.h" -#include "RenderCreatePicture.h" -#include "RenderChangePicture.h" -#include "RenderFreePicture.h" -#include "RenderPictureClip.h" -#include "RenderPictureTransform.h" -#include "RenderPictureFilter.h" -#include "RenderCreateGlyphSet.h" -#include "RenderFreeGlyphSet.h" -#include "RenderAddGlyphs.h" -#include "RenderComposite.h" -#include "RenderCompositeGlyphs.h" -#include "RenderFillRectangles.h" -#include "RenderTrapezoids.h" -#include "RenderTriangles.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Constructor and destructor. -// - -RenderExtensionStore::RenderExtensionStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = RENDEREXTENSION_ENABLE_CACHE; - enableData = RENDEREXTENSION_ENABLE_DATA; - enableSplit = RENDEREXTENSION_ENABLE_SPLIT; - enableCompress = RENDEREXTENSION_ENABLE_COMPRESS; - - generic_ = new RenderGenericRequestStore(); - - for (int i = 0; i < RENDEREXTENSION_MINOR_OPCODE_LIMIT; i++) - { - minors_[i] = generic_; - } - - minors_[X_RenderChangePicture] = new RenderChangePictureStore(); - minors_[X_RenderFillRectangles] = new RenderFillRectanglesStore(); - minors_[X_RenderAddGlyphs] = new RenderAddGlyphsStore(); - - // Since ProtoStep7 (#issue 108) - minors_[X_RenderCreatePicture] = new RenderCreatePictureStore(); - minors_[X_RenderFreePicture] = new RenderFreePictureStore(); - minors_[X_RenderSetPictureClipRectangles] = new RenderPictureClipStore(); - minors_[X_RenderCreateGlyphSet] = new RenderCreateGlyphSetStore(); - minors_[X_RenderComposite] = new RenderCompositeStore(); - minors_[X_RenderCompositeGlyphs8] = new RenderCompositeGlyphsStore(); - minors_[X_RenderCompositeGlyphs16] = new RenderCompositeGlyphsStore(); - minors_[X_RenderCompositeGlyphs32] = new RenderCompositeGlyphsStore(); - - minors_[X_RenderSetPictureTransform] = new RenderPictureTransformStore(); - minors_[X_RenderSetPictureFilter] = new RenderPictureFilterStore(); - minors_[X_RenderFreeGlyphSet] = new RenderFreeGlyphSetStore(); - minors_[X_RenderTrapezoids] = new RenderTrapezoidsStore(); - minors_[X_RenderTriangles] = new RenderTrianglesStore(); - - dataLimit = RENDEREXTENSION_DATA_LIMIT; - dataOffset = RENDEREXTENSION_DATA_OFFSET; - - // Since ProtoStep7 (#issue 108) - cacheSlots = RENDEREXTENSION_CACHE_SLOTS_IF_PROTO_STEP_7; - - cacheThreshold = RENDEREXTENSION_CACHE_THRESHOLD; - cacheLowerThreshold = RENDEREXTENSION_CACHE_LOWER_THRESHOLD; - - opcode_ = X_NXInternalRenderExtension; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -RenderExtensionStore::~RenderExtensionStore() -{ - for (int i = 0; i < RENDEREXTENSION_MINOR_OPCODE_LIMIT; i++) - { - if (minors_[i] != generic_) - { - delete minors_[i]; - } - } - - delete generic_; - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -int RenderExtensionStore::validateMessage(const unsigned char *buffer, int size) -{ - #ifdef TEST - *logofs << name() << ": Encoding message OPCODE#" - << (unsigned) *buffer << " MINOR#" << (unsigned) - *(buffer + 1) << " with size " << size - << ".\n" << logofs_flush; - #endif - - return (size >= control -> MinimumMessageSize && - size <= control -> MaximumMessageSize); -} - -// -// Here are the methods to handle the messages' content. -// - -int RenderExtensionStore::identitySize(const unsigned char *buffer, unsigned int size) -{ - return minors_[*(buffer + 1)] -> identitySize(buffer, size); -} - -int RenderExtensionStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - encodeBuffer.encodeOpcodeValue(*(buffer + 1), - ((ClientCache *) channelCache) -> renderOpcodeCache); - - minors_[*(buffer + 1)] -> encodeMessage(encodeBuffer, buffer, size, - bigEndian, channelCache); - - return 1; -} - -int RenderExtensionStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - unsigned char type; - - decodeBuffer.decodeOpcodeValue(type, - ((ClientCache *) channelCache) -> renderOpcodeCache); - - minors_[type] -> decodeMessage(decodeBuffer, buffer, size, type, - bigEndian, writeBuffer, channelCache); - - return 1; -} - -int RenderExtensionStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - return minors_[*(buffer + 1)] -> parseIdentity(message, buffer, size, bigEndian); -} - -int RenderExtensionStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - return minors_[((RenderExtensionMessage *) message) -> data.any.type] -> - unparseIdentity(message, buffer, size, bigEndian); -} - -void RenderExtensionStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - minors_[*(buffer + 1)] -> identityChecksum(message, buffer, size, md5_state_, bigEndian); -} - -void RenderExtensionStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - minors_[((RenderExtensionMessage *) message) -> data.any.type] -> - updateIdentity(encodeBuffer, message, cachedMessage, channelCache); -} - -void RenderExtensionStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - minors_[((RenderExtensionMessage *) message) -> data.any.type] -> - updateIdentity(decodeBuffer, message, channelCache); -} - -void RenderExtensionStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - #ifdef WARNING - *logofs << name() << ": WARNING! Dump of identity not implemented.\n" - << logofs_flush; - #endif - - #endif -} - -// -// TODO: The following encoding and decoding functions -// could be generalized further, for example by passing -// the pointer to the data cache, the number of caches -// made available by the caller and the first cache to -// iterate through. -// - -void RenderMinorExtensionStore::encodeLongData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeLongData(buffer + offset, size - offset); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - offset - << " bytes of long data.\n" << logofs_flush; - #endif -} - -void RenderMinorExtensionStore::encodeIntData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeIntData(buffer + offset, size - offset); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - offset - << " bytes of int data.\n" << logofs_flush; - #endif -} - -void RenderMinorExtensionStore::encodeCharData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(buffer + offset, size - offset); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - offset - << " bytes of text data.\n" << logofs_flush; - #endif -} - -void RenderMinorExtensionStore::decodeLongData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeLongData(buffer + offset, size - offset); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - offset - << " bytes of long data.\n" << logofs_flush; - #endif -} - -void RenderMinorExtensionStore::decodeIntData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeIntData(buffer + offset, size - offset); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - offset - << " bytes of int data.\n" << logofs_flush; - #endif -} - -void RenderMinorExtensionStore::decodeCharData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(buffer + offset, size - offset); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - offset - << " bytes of text data.\n" << logofs_flush; - #endif -} - -void RenderMinorExtensionStore::parseIntData(const Message *message, const unsigned char *buffer, - unsigned int offset, unsigned int size, - int bigEndian) const -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - unsigned int last = ((unsigned) message -> i_size_ > size ? size : message -> i_size_); - - for (unsigned int i = offset, c = (offset - 4) % 16; i < last; i += 2) - { - #ifdef DEBUG - *logofs << name() << ": Parsing int with i = " << i << " c = " - << c << ".\n" << logofs_flush; - #endif - - renderExtension -> data.any.short_data[c] = GetUINT(buffer + i, bigEndian); - - if (++c == 16) c = 0; - } -} - -void RenderMinorExtensionStore::unparseIntData(const Message *message, unsigned char *buffer, - unsigned int offset, unsigned int size, - int bigEndian) const -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - unsigned int last = ((unsigned) message -> i_size_ > size ? size : message -> i_size_); - - for (unsigned int i = offset, c = (offset - 4) % 16; i < last; i += 2) - { - #ifdef DEBUG - *logofs << name() << ": Unparsing int with i = " << i << " c = " - << c << ".\n" << logofs_flush; - #endif - - PutUINT(renderExtension -> data.any.short_data[c], buffer + i, bigEndian); - - if (++c == 16) c = 0; - } -} - -void RenderMinorExtensionStore::updateIntData(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, unsigned int offset, - unsigned int size, ChannelCache *channelCache) const -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int last = ((unsigned) message -> i_size_ > size ? size : message -> i_size_); - - for (unsigned int i = offset, c = (offset - 4) % 16; i < last; i += 2) - { - #ifdef DEBUG - *logofs << name() << ": Encoding int update with i = " << i - << " c = " << c << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(renderExtension -> data.any.short_data[c], 16, - *clientCache -> renderDataCache[c]); - - cachedRenderExtension -> data.any.short_data[c] = - renderExtension -> data.any.short_data[c]; - - if (++c == 16) c = 0; - } -} - -void RenderMinorExtensionStore::updateIntData(DecodeBuffer &decodeBuffer, const Message *message, - unsigned int offset, unsigned int size, - ChannelCache *channelCache) const -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int last = ((unsigned) message -> i_size_ > size ? size : message -> i_size_); - - unsigned int value; - - for (unsigned int i = offset, c = (offset - 4) % 16; i < last; i += 2) - { - #ifdef DEBUG - *logofs << name() << ": Decoding int update with i = " << i - << " c = " << c << ".\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache -> renderDataCache[c]); - - renderExtension -> data.any.short_data[c] = value; - - if (++c == 16) c = 0; - } -} diff --git a/nxcomp/RenderExtension.h b/nxcomp/RenderExtension.h deleted file mode 100644 index aa9db1b55..000000000 --- a/nxcomp/RenderExtension.h +++ /dev/null @@ -1,504 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderExtension_H -#define RenderExtension_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Compression of data part is not enabled as -// most messages of this type are smaller than -// the current data size compression threshold. -// - -#define RENDEREXTENSION_ENABLE_CACHE 1 -#define RENDEREXTENSION_ENABLE_DATA 0 -#define RENDEREXTENSION_ENABLE_SPLIT 0 -#define RENDEREXTENSION_ENABLE_COMPRESS 0 - -#define RENDEREXTENSION_DATA_LIMIT 6144 -#define RENDEREXTENSION_DATA_OFFSET 36 - -#define RENDEREXTENSION_CACHE_THRESHOLD 20 -#define RENDEREXTENSION_CACHE_LOWER_THRESHOLD 10 - -#define RENDEREXTENSION_CACHE_SLOTS_IF_PROTO_STEP_7 8000 - -// -// Used to build the table of minor opcodes. -// - -#define RENDEREXTENSION_MINOR_OPCODE_LIMIT 256 - -// -// The message class. -// - -class RenderMinorExtensionStore; - -class RenderExtensionMessage : public Message -{ - friend class RenderExtensionStore; - friend class RenderMinorExtensionStore; - - friend class RenderGenericRequestStore; - friend class RenderCreatePictureStore; - friend class RenderChangePictureStore; - friend class RenderFreePictureStore; - friend class RenderPictureClipStore; - friend class RenderPictureTransformStore; - friend class RenderPictureFilterStore; - friend class RenderCreateGlyphSetStore; - friend class RenderFreeGlyphSetStore; - friend class RenderAddGlyphsStore; - friend class RenderCompositeStore; - friend class RenderCompositeGlyphsStore; - friend class RenderFillRectanglesStore; - friend class RenderTrapezoidsStore; - friend class RenderTrianglesStore; - - public: - - RenderExtensionMessage() - { - } - - ~RenderExtensionMessage() - { - } - - // - // We consider for this message a data offset of 36, - // that is size of the biggest among all requests of - // this extension. The most common requests have a - // specific differential encoding, others are simply - // encoded through an array of int or char caches. - // - - private: - - union - { - struct - { - unsigned char type; - - unsigned char char_data[32]; - unsigned short short_data[16]; - unsigned short long_data[8]; - } - any; - - struct - { - unsigned char type; - - unsigned int src_id; - unsigned int dst_id; - - unsigned int format; - unsigned int mask; - } - create_picture; - - struct - { - unsigned char type; - - unsigned int src_id; - } - change_picture; - - struct - { - unsigned char type; - - unsigned int src_id; - } - free_picture; - - struct - { - unsigned char type; - - unsigned int src_id; - - unsigned short src_x; - unsigned short src_y; - } - picture_clip; - - struct - { - unsigned char type; - - unsigned int src_id; - } - picture_transform; - - struct - { - unsigned char type; - - unsigned int src_id; - unsigned int num_elm; - } - picture_filter; - - struct - { - unsigned char type; - - unsigned int set_id; - unsigned int format; - } - create_set; - - struct - { - unsigned char type; - - unsigned int set_id; - } - free_set; - - struct - { - unsigned char type; - - unsigned int set_id; - unsigned int num_elm; - } - add_glyphs; - - struct - { - unsigned char type; - - unsigned char op; - - unsigned int src_id; - unsigned int msk_id; - unsigned int dst_id; - - unsigned short src_x; - unsigned short src_y; - - unsigned short msk_x; - unsigned short msk_y; - - unsigned short dst_x; - unsigned short dst_y; - - unsigned short width; - unsigned short height; - } - composite; - - struct - { - unsigned char type; - - unsigned char op; - - unsigned char num_elm; - - unsigned int src_id; - unsigned int dst_id; - - unsigned int format; - unsigned int set_id; - - unsigned short src_x; - unsigned short src_y; - - unsigned short offset_x; - unsigned short offset_y; - } - composite_glyphs; - - struct - { - unsigned char type; - - unsigned char op; - - unsigned int dst_id; - } - fill_rectangles; - - struct - { - unsigned char type; - - unsigned char op; - - unsigned int src_id; - unsigned int dst_id; - - unsigned int format; - - unsigned short src_x; - unsigned short src_y; - } - trapezoids; - - struct - { - unsigned char type; - - unsigned char op; - - unsigned int src_id; - unsigned int dst_id; - - unsigned int format; - - unsigned short src_x; - unsigned short src_y; - } - triangles; - - struct - { - unsigned char type; - - unsigned char op; - - unsigned char num_elm; - - unsigned int src_id; - unsigned int dst_id; - - unsigned int format; - unsigned int set_id; - - unsigned short src_x; - unsigned short src_y; - - unsigned short delta_x; - unsigned short delta_y; - } - composite_glyphs_compat; - - } - data; -}; - -class RenderExtensionStore : public MessageStore -{ - public: - - RenderExtensionStore(StaticCompressor *compressor); - - virtual ~RenderExtensionStore(); - - virtual const char *name() const - { - return "RenderExtension"; - } - - virtual unsigned char opcode() const - { - return opcode_; - } - - virtual unsigned int storage() const - { - return sizeof(RenderExtensionMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new RenderExtensionMessage(); - } - - virtual Message *create(const Message &message) const - { - return new RenderExtensionMessage((const RenderExtensionMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (RenderExtensionMessage *) message; - } - - // - // Determine if the message must be stored - // in the cache. - // - - virtual int validateMessage(const unsigned char *buffer, int size); - - // - // Since protocol step 5 these methods are - // specialized in their minor opcode stores. - // - - virtual int identitySize(const unsigned char *buffer, unsigned int size); - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; - - private: - - unsigned char opcode_; - - // - // Keep pointers to specialized classes. - // - - RenderMinorExtensionStore *minors_[RENDEREXTENSION_MINOR_OPCODE_LIMIT]; - - RenderMinorExtensionStore *generic_; -}; - -class RenderMinorExtensionStore : public MinorMessageStore -{ - public: - - virtual const char *name() const = 0; - - virtual int identitySize(const unsigned char *buffer, unsigned int size) = 0; - - virtual int encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const = 0; - - virtual int decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, unsigned char type, int bigEndian, - WriteBuffer *writeBuffer, ChannelCache *channelCache) const = 0; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const = 0; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const = 0; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const = 0; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const = 0; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, md5_state_t *md5_state, - int bigEndian) const = 0; - - // - // Internal encode and decode utilities. - // - - protected: - - void encodeLongData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - void encodeIntData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - void encodeCharData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - void decodeLongData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - void decodeIntData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - void decodeCharData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int offset, unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - /* - * The following methods are only used in the - * encoding of the generic render request. To - * be removed in future. - */ - - void parseIntData(const Message *message, const unsigned char *buffer, - unsigned int offset, unsigned int size, - int bigEndian) const; - - void unparseIntData(const Message *message, unsigned char *buffer, - unsigned int offset, unsigned int size, - int bigEndian) const; - - void updateIntData(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, unsigned int offset, - unsigned int size, ChannelCache *channelCache) const; - - void updateIntData(DecodeBuffer &decodeBuffer, const Message *message, - unsigned int offset, unsigned int size, - ChannelCache *channelCache) const; -}; - -#endif /* RenderExtension_H */ diff --git a/nxcomp/RenderFillRectangles.cpp b/nxcomp/RenderFillRectangles.cpp deleted file mode 100644 index a6f2c0e0d..000000000 --- a/nxcomp/RenderFillRectangles.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderFillRectangles.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - // - // The color structure (4 components, 2 bytes - // each) is included in the data part, so that - // it gets into the checksum. The rectangles - // are in the format x, y, width, height with - // 2 bytes per each field, so each request is - // at least 12 + 8 + 8 = 28 bytes long. - // - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - size = MESSAGE_OFFSET + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), - clientCache -> renderSrcPictureCache); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - decodeBuffer.decodeXidValue(value, clientCache -> renderSrcPictureCache); - - PutULONG(value, buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - encodeIntData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - decodeIntData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.fill_rectangles.type = *(buffer + 1); - renderExtension -> data.fill_rectangles.op = *(buffer + 4); - - renderExtension -> data.fill_rectangles.dst_id = GetULONG(buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.fill_rectangles.type << " size is " - << renderExtension -> size_ << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.fill_rectangles.type; - *(buffer + 4) = renderExtension -> data.fill_rectangles.op; - - PutULONG(renderExtension -> data.fill_rectangles.dst_id, buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.fill_rectangles.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - md5_append(md5_state, buffer + 1, 4); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(renderExtension -> data.fill_rectangles.dst_id, - clientCache -> renderSrcPictureCache); - - cachedRenderExtension -> data.fill_rectangles.dst_id = - renderExtension -> data.fill_rectangles.dst_id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.fill_rectangles.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(renderExtension -> data.fill_rectangles.dst_id, - clientCache -> renderSrcPictureCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.fill_rectangles.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderFillRectangles.h b/nxcomp/RenderFillRectangles.h deleted file mode 100644 index 9efaeffa8..000000000 --- a/nxcomp/RenderFillRectangles.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderFillRectangles_H -#define RenderFillRectangles_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderFillRectangles" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderFillRectanglesStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 12 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderFillRectangles_H */ diff --git a/nxcomp/RenderFreeGlyphSet.cpp b/nxcomp/RenderFreeGlyphSet.cpp deleted file mode 100644 index cf1261ac0..000000000 --- a/nxcomp/RenderFreeGlyphSet.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderFreeGlyphSet.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeFreeXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> renderFreeGlyphSetCache); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - unsigned int value; - - ClientCache *clientCache = (ClientCache *) channelCache; - - *(buffer + 1) = type; - - decodeBuffer.decodeFreeXidValue(value, - clientCache -> renderFreeGlyphSetCache); - - PutULONG(value, buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.free_set.type = *(buffer + 1); - - renderExtension -> data.free_set.set_id = GetULONG(buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.free_set.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.free_set.type; - - PutULONG(renderExtension -> data.free_set.set_id, buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.free_set.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - md5_append(md5_state, buffer + 1, 3); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeFreeXidValue(renderExtension -> data.free_set.set_id, - clientCache -> renderFreeGlyphSetCache); - - cachedRenderExtension -> data.free_set.set_id = - renderExtension -> data.free_set.set_id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.free_set.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeFreeXidValue(renderExtension -> data.free_set.set_id, - clientCache -> renderFreeGlyphSetCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.free_set.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderFreeGlyphSet.h b/nxcomp/RenderFreeGlyphSet.h deleted file mode 100644 index 8817e8d99..000000000 --- a/nxcomp/RenderFreeGlyphSet.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderFreeGlyphSet_H -#define RenderFreeGlyphSet_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderFreeGlyphSet" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderFreeGlyphSetStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 8 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 0 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 0 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderFreeGlyphSet_H */ diff --git a/nxcomp/RenderFreePicture.cpp b/nxcomp/RenderFreePicture.cpp deleted file mode 100644 index 3d468624a..000000000 --- a/nxcomp/RenderFreePicture.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderFreePicture.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeFreeXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> renderFreePictureCache); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - unsigned int value; - - ClientCache *clientCache = (ClientCache *) channelCache; - - *(buffer + 1) = type; - - decodeBuffer.decodeFreeXidValue(value, - clientCache -> renderFreePictureCache); - - PutULONG(value, buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.free_picture.type = *(buffer + 1); - - renderExtension -> data.free_picture.src_id = GetULONG(buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.free_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.free_picture.type; - - PutULONG(renderExtension -> data.free_picture.src_id, buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.free_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - md5_append(md5_state, buffer + 1, 3); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeFreeXidValue(renderExtension -> data.free_picture.src_id, - clientCache -> renderFreePictureCache); - - cachedRenderExtension -> data.free_picture.src_id = - renderExtension -> data.free_picture.src_id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.free_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeFreeXidValue(renderExtension -> data.free_picture.src_id, - clientCache -> renderFreePictureCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.free_picture.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderFreePicture.h b/nxcomp/RenderFreePicture.h deleted file mode 100644 index b50191a72..000000000 --- a/nxcomp/RenderFreePicture.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderFreePicture_H -#define RenderFreePicture_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderFreePicture" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderFreePictureStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 8 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 0 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 0 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderFreePicture_H */ diff --git a/nxcomp/RenderGenericRequest.cpp b/nxcomp/RenderGenericRequest.cpp deleted file mode 100644 index fc3210ba2..000000000 --- a/nxcomp/RenderGenericRequest.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "NXrender.h" - -#include "RenderExtension.h" -#include "RenderGenericRequest.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Here are the methods to handle the messages' content. -// - -int RenderGenericRequestStore::encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message.\n" - << logofs_flush; - - unsigned char type = *(buffer + 1); - - #endif - - encodeBuffer.encodeCachedValue(size >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef DEBUG - *logofs << name() << ": Encoding full unhandled message. " - << "Type is " << (unsigned int) type << " size is " - << size << ".\n" << logofs_flush; - #endif - - encodeIntData(encodeBuffer, buffer, 4, size, - bigEndian, clientCache); - - #ifdef DEBUG - *logofs << name() << ": Encoded full message.\n" - << logofs_flush; - #endif - - return 1; -} - -int RenderGenericRequestStore::decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, unsigned char type, int bigEndian, - WriteBuffer *writeBuffer, ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message.\n" - << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - size <<= 2; - - buffer = writeBuffer -> addMessage(size); - - *(buffer + 1) = type; - - #ifdef DEBUG - *logofs << name() << ": Decoding full unhandled message. " - << "Type is " << (unsigned int) type << " size is " - << size << ".\n" << logofs_flush; - #endif - - decodeIntData(decodeBuffer, buffer, 4, size, - bigEndian, clientCache); - - #ifdef DEBUG - *logofs << name() << ": Decoded full message.\n" - << logofs_flush; - #endif - - return 1; -} - -void RenderGenericRequestStore::encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ -} - -void RenderGenericRequestStore::decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ -} - -int RenderGenericRequestStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - #ifdef DEBUG - *logofs << name() << ": Parsing identity for message at " - << this << ".\n" << logofs_flush; - #endif - - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - unsigned char type = *(buffer + 1); - - renderExtension -> data.any.type = type; - - #ifdef DEBUG - *logofs << name() << ": Parsing unhandled identity. " - << "Type is " << (unsigned int) renderExtension -> data.any.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif - - parseIntData(message, buffer, 4, size, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int RenderGenericRequestStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - #ifdef DEBUG - *logofs << name() << ": Unparsing identity for message at " - << this << ".\n" << logofs_flush; - #endif - - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - unsigned char type = renderExtension -> data.any.type; - - *(buffer + 1) = type; - - #ifdef DEBUG - *logofs << name() << ": Unparsing unhandled identity. " - << "Type is " << (unsigned int) renderExtension -> data.any.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif - - unparseIntData(message, buffer, 4, size, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void RenderGenericRequestStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, md5_state_t *md5_state, - int bigEndian) const -{ - // - // Include the minor opcode in the checksum. - // Because the data offset can be beyond the - // real end of the message, we need to include - // the size or we will match any message whose - // size is less or equal to the data offset. - // - - md5_append(md5_state, buffer + 1, 3); -} - -void RenderGenericRequestStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - // - // Encode the variant part. - // - - #ifdef DEBUG - *logofs << name() << ": Updating identity for message at " - << this << ".\n" << logofs_flush; - #endif - - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - #ifdef DEBUG - *logofs << name() << ": Encoding unhandled update. " - << "Type is " << (unsigned int) renderExtension -> data.any.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif - - updateIntData(encodeBuffer, message, cachedMessage, 4, - renderExtension -> size_, channelCache); - - #ifdef DEBUG - *logofs << name() << ": Updated identity for message at " - << this << ".\n" << logofs_flush; - #endif -} - -void RenderGenericRequestStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - #ifdef DEBUG - *logofs << name() << ": Updating identity for message at " - << this << ".\n" << logofs_flush; - #endif - - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - #ifdef DEBUG - *logofs << name() << ": Decoding unhandled update. " - << "Type is " << (unsigned int) renderExtension -> data.any.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif - - updateIntData(decodeBuffer, message, 4, - renderExtension -> size_, channelCache); - - #ifdef DEBUG - *logofs << name() << ": Updated identity for message at " - << this << ".\n" << logofs_flush; - #endif -} diff --git a/nxcomp/RenderGenericRequest.h b/nxcomp/RenderGenericRequest.h deleted file mode 100644 index fdf5ca876..000000000 --- a/nxcomp/RenderGenericRequest.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderGenericRequest_H -#define RenderGenericRequest_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -class RenderGenericRequestStore : public RenderMinorExtensionStore -{ - public: - - virtual const char *name() const - { - return "RenderGenericRequest"; - } - - virtual int identitySize(const unsigned char *buffer, unsigned int size) - { - return RENDEREXTENSION_DATA_OFFSET; - } - - virtual int encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, unsigned char type, int bigEndian, - WriteBuffer *writeBuffer, ChannelCache *channelCache) const; - - virtual void encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual void decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, md5_state_t *md5_state, - int bigEndian) const; -}; - -#endif /* RenderGenericRequest_H */ diff --git a/nxcomp/RenderMinorExtensionHeaders.h b/nxcomp/RenderMinorExtensionHeaders.h deleted file mode 100644 index b7f6efc5a..000000000 --- a/nxcomp/RenderMinorExtensionHeaders.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderMinorExtensionHeaders_H -#define RenderMinorExtensionHeaders_H - -#include "NXrender.h" - -#include "Message.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -#include "RenderExtension.h" - -#endif /* RenderMinorExtensionHeaders_H */ diff --git a/nxcomp/RenderMinorExtensionMethods.h b/nxcomp/RenderMinorExtensionMethods.h deleted file mode 100644 index d272337e0..000000000 --- a/nxcomp/RenderMinorExtensionMethods.h +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// This file is included multiple times, -// one for each message inheriting the -// parent class. -// - -public: - -#if MESSAGE_HAS_SIZE - -virtual void encodeSize(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - -virtual void decodeSize(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, unsigned char type, int bigEndian, - WriteBuffer *writeBuffer, ChannelCache *channelCache) const; - -#endif - -#if MESSAGE_HAS_DATA - -virtual void encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - -virtual void decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, - unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - -#endif - -virtual int encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - -virtual int decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, unsigned char type, int bigEndian, - WriteBuffer *writeBuffer, ChannelCache *channelCache) const; - -virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - -virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - -virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - -virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - -virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, md5_state_t *md5_state, - int bigEndian) const; diff --git a/nxcomp/RenderMinorExtensionTags.h b/nxcomp/RenderMinorExtensionTags.h deleted file mode 100644 index c24a99638..000000000 --- a/nxcomp/RenderMinorExtensionTags.h +++ /dev/null @@ -1,194 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderMinorExtensionTags_H -#define RenderMinorExtensionTags_H - -// -// Set in the message header file. -// - -#if MESSAGE_HAS_SIZE - -#define MESSAGE_ENCODE_SIZE encodeSize(encodeBuffer, buffer, size, bigEndian, channelCache) -#define MESSAGE_DECODE_SIZE decodeSize(decodeBuffer, buffer, size, type, bigEndian, writeBuffer, channelCache) - -#else - -#define MESSAGE_ENCODE_SIZE -#define MESSAGE_DECODE_SIZE size = MESSAGE_OFFSET; buffer = writeBuffer -> addMessage(size); - -#endif - -#if MESSAGE_HAS_DATA - -#define MESSAGE_ENCODE_DATA encodeData(encodeBuffer, buffer, size, bigEndian, channelCache) -#define MESSAGE_DECODE_DATA decodeData(decodeBuffer, buffer, size, bigEndian, channelCache) - -#else - -#define MESSAGE_ENCODE_DATA -#define MESSAGE_DECODE_DATA - -#endif - -// -// Prologue an epilogue of the message -// handling functions. -// - -#define MESSAGE_BEGIN_ENCODE_SIZE \ -\ -void MESSAGE_STORE::encodeSize(EncodeBuffer &encodeBuffer, const unsigned char *buffer, \ - const unsigned int size, int bigEndian, \ - ChannelCache *channelCache) const \ -{ - -#define MESSAGE_END_ENCODE_SIZE \ -\ -} - -#define MESSAGE_BEGIN_DECODE_SIZE \ -\ -void MESSAGE_STORE::decodeSize(DecodeBuffer &decodeBuffer, unsigned char *&buffer, \ - unsigned int &size, unsigned char type, int bigEndian, \ - WriteBuffer *writeBuffer, ChannelCache *channelCache) const \ -{ - -#define MESSAGE_END_DECODE_SIZE \ -\ -} - -#define MESSAGE_BEGIN_ENCODE_MESSAGE \ -\ -int MESSAGE_STORE::encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, \ - const unsigned int size, int bigEndian, \ - ChannelCache *channelCache) const \ -{ \ - MESSAGE_ENCODE_SIZE; - - -#define MESSAGE_END_ENCODE_MESSAGE \ -\ - MESSAGE_ENCODE_DATA; \ -\ - return 1; \ -} - -#define MESSAGE_BEGIN_DECODE_MESSAGE \ -\ -int MESSAGE_STORE::decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, \ - unsigned int &size, unsigned char type, int bigEndian, \ - WriteBuffer *writeBuffer, ChannelCache *channelCache) const \ -{ \ - MESSAGE_DECODE_SIZE; - - -#define MESSAGE_END_DECODE_MESSAGE \ -\ - MESSAGE_DECODE_DATA; \ -\ - return 1; \ -} - -#define MESSAGE_BEGIN_ENCODE_DATA \ -\ -void MESSAGE_STORE::encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, \ - unsigned int size, int bigEndian, \ - ChannelCache *channelCache) const \ -{ - -#define MESSAGE_END_ENCODE_DATA \ -\ -} - -#define MESSAGE_BEGIN_DECODE_DATA \ -\ -void MESSAGE_STORE::decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, \ - unsigned int size, int bigEndian, \ - ChannelCache *channelCache) const \ -{ - -#define MESSAGE_END_DECODE_DATA \ -\ -} - -#define MESSAGE_BEGIN_PARSE_IDENTITY \ -\ -int MESSAGE_STORE::parseIdentity(Message *message, const unsigned char *buffer, \ - unsigned int size, int bigEndian) const \ -{ - -#define MESSAGE_END_PARSE_IDENTITY \ -\ - return 1; \ -\ -} - -#define MESSAGE_BEGIN_UNPARSE_IDENTITY \ -\ -int MESSAGE_STORE::unparseIdentity(const Message *message, unsigned char *buffer, \ - unsigned int size, int bigEndian) const \ -{ - -#define MESSAGE_END_UNPARSE_IDENTITY \ -\ - return 1; \ -\ -} - -#define MESSAGE_BEGIN_IDENTITY_CHECKSUM \ -\ -void MESSAGE_STORE::identityChecksum(const Message *message, const unsigned char *buffer, \ - unsigned int size, md5_state_t *md5_state, \ - int bigEndian) const \ -{ - -#define MESSAGE_END_IDENTITY_CHECKSUM \ -\ -} - -#define MESSAGE_BEGIN_ENCODE_UPDATE \ -\ -void MESSAGE_STORE::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, \ - const Message *cachedMessage, \ - ChannelCache *channelCache) const \ -{ - -#define MESSAGE_END_ENCODE_UPDATE \ -\ -} - -#define MESSAGE_BEGIN_DECODE_UPDATE \ -\ -void MESSAGE_STORE::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, \ - ChannelCache *channelCache) const \ -{ - -#define MESSAGE_END_DECODE_UPDATE \ -\ -} - -#endif /* RenderMinorExtensionTags_H */ diff --git a/nxcomp/RenderPictureClip.cpp b/nxcomp/RenderPictureClip.cpp deleted file mode 100644 index 32d526c81..000000000 --- a/nxcomp/RenderPictureClip.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderPictureClip.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - // - // The data is constituted by a number of - // rectangles. Each rectangle is in the - // format x, y, width, height with 2 bytes - // per each field, so each request is at - // least 12 + 8 = 20 bytes long. - // - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - size = MESSAGE_OFFSET + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> renderSrcPictureCache); - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 8, bigEndian), - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 10, bigEndian), - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeXidValue(value, - clientCache -> renderSrcPictureCache); - - PutULONG(value, buffer + 4, bigEndian); - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - PutUINT(clientCache -> renderLastX, buffer + 8, bigEndian); - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - PutUINT(clientCache -> renderLastY, buffer + 10, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - encodeIntData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - decodeIntData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.picture_clip.type = *(buffer + 1); - - renderExtension -> data.picture_clip.src_id = GetULONG(buffer + 4, bigEndian); - - renderExtension -> data.picture_clip.src_x = GetUINT(buffer + 8, bigEndian); - renderExtension -> data.picture_clip.src_y = GetUINT(buffer + 10, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.picture_clip.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.picture_clip.type; - - PutULONG(renderExtension -> data.picture_clip.src_id, buffer + 4, bigEndian); - - PutUINT(renderExtension -> data.picture_clip.src_x, buffer + 8, bigEndian); - PutUINT(renderExtension -> data.picture_clip.src_y, buffer + 10, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.picture_clip.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - // - // Encode the picture id and the - // source x and y differentially. - // - - md5_append(md5_state, buffer + 1, 3); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(renderExtension -> data.picture_clip.src_id, - clientCache -> renderSrcPictureCache); - - cachedRenderExtension -> data.picture_clip.src_id = - renderExtension -> data.picture_clip.src_id; - - // - // The source x and y coordinates are - // encoded as differerences in respect - // to the previous cached value. - // - - unsigned int value; - unsigned int previous; - - value = renderExtension -> data.picture_clip.src_x; - previous = cachedRenderExtension -> data.picture_clip.src_x; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderXCache, 11); - - cachedRenderExtension -> data.picture_clip.src_x = value; - - value = renderExtension -> data.picture_clip.src_y; - previous = cachedRenderExtension -> data.picture_clip.src_y; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderYCache, 11); - - cachedRenderExtension -> data.picture_clip.src_y = value; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.picture_clip.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(renderExtension -> data.picture_clip.src_id, - clientCache -> renderSrcPictureCache); - - unsigned int value; - unsigned int previous; - - previous = renderExtension -> data.picture_clip.src_x; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderXCache, 11); - - renderExtension -> data.picture_clip.src_x = value; - - previous = renderExtension -> data.picture_clip.src_y; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderYCache, 11); - - renderExtension -> data.picture_clip.src_y = value; - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.picture_clip.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderPictureClip.h b/nxcomp/RenderPictureClip.h deleted file mode 100644 index bd811dfcd..000000000 --- a/nxcomp/RenderPictureClip.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderPictureClip_H -#define RenderPictureClip_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderPictureClip" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderPictureClipStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 12 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderPictureClip_H */ diff --git a/nxcomp/RenderPictureFilter.cpp b/nxcomp/RenderPictureFilter.cpp deleted file mode 100644 index 9598601c2..000000000 --- a/nxcomp/RenderPictureFilter.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderPictureFilter.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding value " - << ((size - MESSAGE_OFFSET) >> 2) << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << size - << ".\n" << logofs_flush; - #endif - - size = MESSAGE_OFFSET + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> renderSrcPictureCache); - - encodeBuffer.encodeCachedValue(GetUINT(buffer + 8, bigEndian), 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeXidValue(value, - clientCache -> renderSrcPictureCache); - - PutULONG(value, buffer + 4, bigEndian); - - decodeBuffer.decodeCachedValue(value, 16, - clientCache -> renderLengthCache, 5); - - PutUINT(value, buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.picture_filter.type = *(buffer + 1); - - renderExtension -> data.picture_filter.src_id = GetULONG(buffer + 4, bigEndian); - renderExtension -> data.picture_filter.num_elm = GetUINT(buffer + 8, bigEndian); - - // - // Clean the padding bytes. This - // should be the purpose of the - // filter. - // - - #ifdef TEST - *logofs << name() << ": Cleaning " - << RoundUp4(renderExtension -> data.picture_filter.num_elm) - - renderExtension -> data.picture_filter.num_elm << " bytes " - << "at offset " << MESSAGE_OFFSET + renderExtension -> - data.picture_filter.num_elm << " with " << renderExtension -> - data.picture_filter.num_elm << " elements and size " - << renderExtension -> size_ << ".\n" << logofs_flush; - #endif - - if (size >= MESSAGE_OFFSET + renderExtension -> - data.picture_filter.num_elm) - { - unsigned char *next = (unsigned char *) buffer + - MESSAGE_OFFSET + renderExtension -> - data.picture_filter.num_elm; - - while (next < buffer + size) - { - *next++ = '\0'; - } - } - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.picture_filter.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.picture_filter.type; - - PutULONG(renderExtension -> data.picture_filter.src_id, buffer + 4, bigEndian); - PutUINT(renderExtension -> data.picture_filter.num_elm, buffer + 8, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.picture_filter.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - // - // Include the length of the filter name - // in the checksum. - // - - md5_append(md5_state, buffer + 1, 3); - md5_append(md5_state, buffer + 8, 2); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(renderExtension -> data.picture_filter.src_id, - clientCache -> renderSrcPictureCache); - - cachedRenderExtension -> data.picture_filter.src_id = - renderExtension -> data.picture_filter.src_id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.picture_filter.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(renderExtension -> data.picture_filter.src_id, - clientCache -> renderSrcPictureCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.picture_filter.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderPictureFilter.h b/nxcomp/RenderPictureFilter.h deleted file mode 100644 index a3e37538b..000000000 --- a/nxcomp/RenderPictureFilter.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderPictureFilter_H -#define RenderPictureFilter_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderPictureFilter" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderPictureFilterStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 12 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderPictureFilter_H */ diff --git a/nxcomp/RenderPictureTransform.cpp b/nxcomp/RenderPictureTransform.cpp deleted file mode 100644 index 053748bd3..000000000 --- a/nxcomp/RenderPictureTransform.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderPictureTransform.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - // - // Size is always 44. The identity size - // is set to 8, so we encode the 36 bytes - // of the transformation matrix as our - // data. - // -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - size = MESSAGE_OFFSET + 36; - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), - clientCache -> renderSrcPictureCache); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeXidValue(value, - clientCache -> renderSrcPictureCache); - - PutULONG(value, buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.picture_transform.type = *(buffer + 1); - - renderExtension -> data.picture_transform.src_id = GetULONG(buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.picture_transform.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.picture_transform.type; - - PutULONG(renderExtension -> data.picture_transform.src_id, buffer + 4, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.picture_transform.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - md5_append(md5_state, buffer + 1, 3); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(renderExtension -> data.picture_transform.src_id, - clientCache -> renderSrcPictureCache); - - cachedRenderExtension -> data.picture_transform.src_id = - renderExtension -> data.picture_transform.src_id; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.picture_transform.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(renderExtension -> data.picture_transform.src_id, - clientCache -> renderSrcPictureCache); - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.picture_transform.type - << " size is " << renderExtension -> size_ << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderPictureTransform.h b/nxcomp/RenderPictureTransform.h deleted file mode 100644 index 649cd05d3..000000000 --- a/nxcomp/RenderPictureTransform.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderPictureTransform_H -#define RenderPictureTransform_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderPictureTransform" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderPictureTransformStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 8 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return MESSAGE_OFFSET; - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderPictureTransform_H */ diff --git a/nxcomp/RenderTrapezoids.cpp b/nxcomp/RenderTrapezoids.cpp deleted file mode 100644 index 85f4cad05..000000000 --- a/nxcomp/RenderTrapezoids.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderTrapezoids.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - // - // The trapezoid data is made up of a structure - // containing a top and bottom coordinate in 4 - // bytes format, plus two lines, each represent- - // ed as four points in 4 bytes format. Thus - // each trapezoid is 4 * 2 + (4 * 4) * 2 = 40 - // bytes. Bytes are all padded to an long int, - // so we don't need to clean the message. - // - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding value " - << ((size - MESSAGE_OFFSET) >> 2) << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << size - << ".\n" << logofs_flush; - #endif - - size = MESSAGE_OFFSET + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), - clientCache -> renderSrcPictureCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 12, bigEndian), - clientCache -> renderDstPictureCache); - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 32, - clientCache -> renderFormatCache); - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 20, bigEndian), - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 22, bigEndian), - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - decodeBuffer.decodeXidValue(value, - clientCache -> renderSrcPictureCache); - - PutULONG(value, buffer + 8, bigEndian); - - decodeBuffer.decodeXidValue(value, - clientCache -> renderDstPictureCache); - - PutULONG(value, buffer + 12, bigEndian); - - decodeBuffer.decodeCachedValue(value, 32, - clientCache -> renderFormatCache); - - PutULONG(value, buffer + 16, bigEndian); - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - PutUINT(clientCache -> renderLastX, buffer + 20, bigEndian); - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - PutUINT(clientCache -> renderLastY, buffer + 22, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - if (size > MESSAGE_OFFSET) - { - encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - } - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of text data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - if (size > MESSAGE_OFFSET) - { - decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - } - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.trapezoids.type = *(buffer + 1); - renderExtension -> data.trapezoids.op = *(buffer + 4); - - renderExtension -> data.trapezoids.src_id = GetULONG(buffer + 8, bigEndian); - renderExtension -> data.trapezoids.dst_id = GetULONG(buffer + 12, bigEndian); - - renderExtension -> data.trapezoids.format = GetULONG(buffer + 16, bigEndian); - - renderExtension -> data.trapezoids.src_x = GetUINT(buffer + 20, bigEndian); - renderExtension -> data.trapezoids.src_y = GetUINT(buffer + 22, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.trapezoids.type - << " size is " << renderExtension -> size_ << " identity size " - << renderExtension -> i_size_ << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.trapezoids.type; - *(buffer + 4) = renderExtension -> data.trapezoids.op; - - PutULONG(renderExtension -> data.trapezoids.src_id, buffer + 8, bigEndian); - PutULONG(renderExtension -> data.trapezoids.dst_id, buffer + 12, bigEndian); - - PutULONG(renderExtension -> data.trapezoids.format, buffer + 16, bigEndian); - - PutUINT(renderExtension -> data.trapezoids.src_x, buffer + 20, bigEndian); - PutUINT(renderExtension -> data.trapezoids.src_y, buffer + 22, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.trapezoids.type - << " size is " << renderExtension -> size_ << " identity size " - << renderExtension -> i_size_ << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - // - // Include minor opcode, size and the - // operator in the identity. - // - - md5_append(md5_state, buffer + 1, 4); - - // - // Also include the format but not the - // x and y source. - // - - md5_append(md5_state, buffer + 16, 4); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(renderExtension -> data.trapezoids.src_id, - clientCache -> renderSrcPictureCache); - - cachedRenderExtension -> data.trapezoids.src_id = - renderExtension -> data.trapezoids.src_id; - - encodeBuffer.encodeXidValue(renderExtension -> data.trapezoids.dst_id, - clientCache -> renderDstPictureCache); - - cachedRenderExtension -> data.trapezoids.dst_id = - renderExtension -> data.trapezoids.dst_id; - - // - // The source x and y coordinates are - // encoded as differerences in respect - // to the previous cached value. - // - - unsigned int value; - unsigned int previous; - - value = renderExtension -> data.trapezoids.src_x; - previous = cachedRenderExtension -> data.trapezoids.src_x; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderXCache, 11); - - cachedRenderExtension -> data.trapezoids.src_x = value; - - value = renderExtension -> data.trapezoids.src_y; - previous = cachedRenderExtension -> data.trapezoids.src_y; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderYCache, 11); - - cachedRenderExtension -> data.trapezoids.src_y = value; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.trapezoids.type - << " size is " << renderExtension -> size_ << " source x " - << renderExtension -> data.trapezoids.src_x << " y " - << renderExtension -> data.trapezoids.src_y << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(renderExtension -> data.trapezoids.src_id, - clientCache -> renderSrcPictureCache); - - decodeBuffer.decodeXidValue(renderExtension -> data.trapezoids.dst_id, - clientCache -> renderDstPictureCache); - - unsigned int value; - unsigned int previous; - - previous = renderExtension -> data.trapezoids.src_x; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderXCache, 11); - - renderExtension -> data.trapezoids.src_x = value; - - previous = renderExtension -> data.trapezoids.src_y; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderYCache, 11); - - renderExtension -> data.trapezoids.src_y = value; - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.trapezoids.type - << " size is " << renderExtension -> size_ << " source x " - << renderExtension -> data.trapezoids.src_x << " y " - << renderExtension -> data.trapezoids.src_y << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderTrapezoids.h b/nxcomp/RenderTrapezoids.h deleted file mode 100644 index faf524c76..000000000 --- a/nxcomp/RenderTrapezoids.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderTrapezoids_H -#define RenderTrapezoids_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderTrapezoids" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderTrapezoidsStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 24 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return (size >= MESSAGE_OFFSET ? MESSAGE_OFFSET : size); - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderTrapezoids_H */ diff --git a/nxcomp/RenderTriangles.cpp b/nxcomp/RenderTriangles.cpp deleted file mode 100644 index 746a8e278..000000000 --- a/nxcomp/RenderTriangles.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -// -// Include the template for -// this message class. -// - -#include "RenderTriangles.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#include MESSAGE_TAGS - -// -// Message handling methods. -// - -MESSAGE_BEGIN_ENCODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding value " - << ((size - MESSAGE_OFFSET) >> 2) << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, - clientCache -> renderLengthCache, 5); - - #ifdef TEST - *logofs << name() << ": Encoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_SIZE - -MESSAGE_BEGIN_DECODE_SIZE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(size, 16, - clientCache -> renderLengthCache, 5); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << size - << ".\n" << logofs_flush; - #endif - - size = MESSAGE_OFFSET + (size << 2); - - buffer = writeBuffer -> addMessage(size); - - #ifdef TEST - *logofs << name() << ": Decoded size with value " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_SIZE - -MESSAGE_BEGIN_ENCODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), - clientCache -> renderSrcPictureCache); - - encodeBuffer.encodeXidValue(GetULONG(buffer + 12, bigEndian), - clientCache -> renderDstPictureCache); - - encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 32, - clientCache -> renderFormatCache); - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 20, bigEndian), - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 22, bigEndian), - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - #ifdef TEST - *logofs << name() << ": Encoded message. Type is " - << (unsigned int) *(buffer + 1) << " size is " - << size << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_MESSAGE - -MESSAGE_BEGIN_DECODE_MESSAGE -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - *(buffer + 1) = type; - - decodeBuffer.decodeCachedValue(*(buffer + 4), 8, - clientCache -> renderOpCache); - - decodeBuffer.decodeXidValue(value, - clientCache -> renderSrcPictureCache); - - PutULONG(value, buffer + 8, bigEndian); - - decodeBuffer.decodeXidValue(value, - clientCache -> renderDstPictureCache); - - PutULONG(value, buffer + 12, bigEndian); - - decodeBuffer.decodeCachedValue(value, 32, - clientCache -> renderFormatCache); - - PutULONG(value, buffer + 16, bigEndian); - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastX, 16, - clientCache -> renderXCache, 11); - - PutUINT(clientCache -> renderLastX, buffer + 20, bigEndian); - - decodeBuffer.decodeDiffCachedValue(value, - clientCache -> renderLastY, 16, - clientCache -> renderYCache, 11); - - PutUINT(clientCache -> renderLastY, buffer + 22, bigEndian); - - #ifdef TEST - *logofs << name() << ": Decoded message. Type is " - << (unsigned int) type << " size is " << size - << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_MESSAGE - -MESSAGE_BEGIN_ENCODE_DATA -{ - if (size > MESSAGE_OFFSET) - { - encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - } - - #ifdef TEST - *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET - << " bytes of text data.\n" << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_DATA - -MESSAGE_BEGIN_DECODE_DATA -{ - if (size > MESSAGE_OFFSET) - { - decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, - size, bigEndian, channelCache); - } - - #ifdef TEST - *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET - << " bytes of data.\n" << logofs_flush; - #endif -} -MESSAGE_END_DECODE_DATA - -MESSAGE_BEGIN_PARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - renderExtension -> data.triangles.type = *(buffer + 1); - renderExtension -> data.triangles.op = *(buffer + 4); - - renderExtension -> data.triangles.src_id = GetULONG(buffer + 8, bigEndian); - renderExtension -> data.triangles.dst_id = GetULONG(buffer + 12, bigEndian); - - renderExtension -> data.triangles.format = GetULONG(buffer + 16, bigEndian); - - renderExtension -> data.triangles.src_x = GetUINT(buffer + 20, bigEndian); - renderExtension -> data.triangles.src_y = GetUINT(buffer + 22, bigEndian); - - #ifdef TEST - *logofs << name() << ": Parsed identity. Type is " - << (unsigned int) renderExtension -> data.triangles.type - << " size is " << renderExtension -> size_ << " identity size " - << renderExtension -> i_size_ << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_PARSE_IDENTITY - -MESSAGE_BEGIN_UNPARSE_IDENTITY -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - *(buffer + 1) = renderExtension -> data.triangles.type; - *(buffer + 4) = renderExtension -> data.triangles.op; - - PutULONG(renderExtension -> data.triangles.src_id, buffer + 8, bigEndian); - PutULONG(renderExtension -> data.triangles.dst_id, buffer + 12, bigEndian); - - PutULONG(renderExtension -> data.triangles.format, buffer + 16, bigEndian); - - PutUINT(renderExtension -> data.triangles.src_x, buffer + 20, bigEndian); - PutUINT(renderExtension -> data.triangles.src_y, buffer + 22, bigEndian); - - #ifdef TEST - *logofs << name() << ": Unparsed identity. Type is " - << (unsigned int) renderExtension -> data.triangles.type - << " size is " << renderExtension -> size_ << " identity size " - << renderExtension -> i_size_ << ".\n" << logofs_flush; - #endif -} -MESSAGE_END_UNPARSE_IDENTITY - -MESSAGE_BEGIN_IDENTITY_CHECKSUM -{ - // - // Include minor opcode, size and the - // operator in the identity. - // - - md5_append(md5_state, buffer + 1, 4); - - // - // Also include the format but not the - // x and y source. - // - - md5_append(md5_state, buffer + 16, 4); -} -MESSAGE_END_IDENTITY_CHECKSUM - -MESSAGE_BEGIN_ENCODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeXidValue(renderExtension -> data.triangles.src_id, - clientCache -> renderSrcPictureCache); - - cachedRenderExtension -> data.triangles.src_id = - renderExtension -> data.triangles.src_id; - - encodeBuffer.encodeXidValue(renderExtension -> data.triangles.dst_id, - clientCache -> renderDstPictureCache); - - cachedRenderExtension -> data.triangles.dst_id = - renderExtension -> data.triangles.dst_id; - - // - // The source x and y coordinates are - // encoded as differerences in respect - // to the previous cached value. - // - - unsigned int value; - unsigned int previous; - - value = renderExtension -> data.triangles.src_x; - previous = cachedRenderExtension -> data.triangles.src_x; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderXCache, 11); - - cachedRenderExtension -> data.triangles.src_x = value; - - value = renderExtension -> data.triangles.src_y; - previous = cachedRenderExtension -> data.triangles.src_y; - - encodeBuffer.encodeDiffCachedValue(value, previous, 16, - clientCache -> renderYCache, 11); - - cachedRenderExtension -> data.triangles.src_y = value; - - #ifdef TEST - *logofs << name() << ": Encoded update. Type is " - << (unsigned int) renderExtension -> data.triangles.type - << " size is " << renderExtension -> size_ << " source x " - << renderExtension -> data.triangles.src_x << " y " - << renderExtension -> data.triangles.src_y << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_ENCODE_UPDATE - -MESSAGE_BEGIN_DECODE_UPDATE -{ - RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeXidValue(renderExtension -> data.triangles.src_id, - clientCache -> renderSrcPictureCache); - - decodeBuffer.decodeXidValue(renderExtension -> data.triangles.dst_id, - clientCache -> renderDstPictureCache); - - unsigned int value; - unsigned int previous; - - previous = renderExtension -> data.triangles.src_x; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderXCache, 11); - - renderExtension -> data.triangles.src_x = value; - - previous = renderExtension -> data.triangles.src_y; - - decodeBuffer.decodeDiffCachedValue(value, previous, 16, - clientCache -> renderYCache, 11); - - renderExtension -> data.triangles.src_y = value; - - #ifdef TEST - *logofs << name() << ": Decoded update. Type is " - << (unsigned int) renderExtension -> data.triangles.type - << " size is " << renderExtension -> size_ << " source x " - << renderExtension -> data.triangles.src_x << " y " - << renderExtension -> data.triangles.src_y << ".\n" - << logofs_flush; - #endif -} -MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/RenderTriangles.h b/nxcomp/RenderTriangles.h deleted file mode 100644 index d73efb7b8..000000000 --- a/nxcomp/RenderTriangles.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef RenderTriangles_H -#define RenderTriangles_H - -// -// Define the characteristics -// of this message class here. -// - -#undef MESSAGE_NAME -#define MESSAGE_NAME "RenderTriangles" - -#undef MESSAGE_STORE -#define MESSAGE_STORE RenderTrianglesStore - -#undef MESSAGE_CLASS -#define MESSAGE_CLASS RenderMinorExtensionStore - -#undef MESSAGE_METHODS -#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" - -#undef MESSAGE_HEADERS -#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" - -#undef MESSAGE_TAGS -#define MESSAGE_TAGS "RenderMinorExtensionTags.h" - -#undef MESSAGE_OFFSET -#define MESSAGE_OFFSET 24 - -#undef MESSAGE_HAS_SIZE -#define MESSAGE_HAS_SIZE 1 - -#undef MESSAGE_HAS_DATA -#define MESSAGE_HAS_DATA 1 - -#undef MESSAGE_HAS_FILTER -#define MESSAGE_HAS_FILTER 0 - -// -// Declare the message class. -// - -#include MESSAGE_HEADERS - -class MESSAGE_STORE : public MESSAGE_CLASS -{ - public: - - virtual const char *name() const - { - return MESSAGE_NAME; - } - - virtual int identitySize(const unsigned char *buffer, - unsigned int size) - { - return (size >= MESSAGE_OFFSET ? MESSAGE_OFFSET : size); - } - - #include MESSAGE_METHODS -}; - -#endif /* RenderTriangles_H */ diff --git a/nxcomp/Rgb.cpp b/nxcomp/Rgb.cpp deleted file mode 100644 index 8946a9fc8..000000000 --- a/nxcomp/Rgb.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "Rgb.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -int UnpackRgb(T_geometry *geometry, unsigned char method, unsigned char *src_data, - int src_size, int dst_bpp, int dst_width, int dst_height, - unsigned char *dst_data, int dst_size) -{ - if (*src_data == 0) - { - if (dst_size != src_size - 1) - { - #ifdef TEST - *logofs << "UnpackRgb: PANIC! Invalid destination size " - << dst_size << " with source " << src_size - << ".\n" << logofs_flush; - #endif - - return -1; - } - - #ifdef TEST - *logofs << "UnpackRgb: Expanding " << src_size - 1 - << " bytes of plain RGB data.\n" << logofs_flush; - #endif - - memcpy(dst_data, src_data + 1, src_size - 1); - - return 1; - } - - unsigned int check_size = dst_size; - - int result = ZDecompress(&unpackStream, dst_data, &check_size, - src_data + 1, src_size - 1); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "UnpackRgb: PANIC! Failure decompressing RGB data. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decompressing RGB data. " - << "Error is '" << zError(result) << "'.\n"; - - return -1; - } - else if (check_size != (unsigned int) dst_size) - { - #ifdef PANIC - *logofs << "UnpackRgb: PANIC! Size mismatch in RGB data. " - << "Resulting size is " << check_size << " with " - << "expected size " << dst_size << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Size mismatch in RGB data. " - << "Resulting size is " << check_size << " with " - << "expected size " << dst_size << ".\n"; - - return -1; - } - - #ifdef TEST - *logofs << "UnpackRgb: Decompressed " << src_size - 1 - << " bytes to " << dst_size << " bytes of RGB data.\n" - << logofs_flush; - #endif - - return 1; -} diff --git a/nxcomp/Rgb.h b/nxcomp/Rgb.h deleted file mode 100644 index ec088dd1b..000000000 --- a/nxcomp/Rgb.h +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Rgb_H -#define Rgb_H - -#include "Unpack.h" - -int UnpackRgb(T_geometry *geometry, unsigned char method, - unsigned char *src_data, int src_size, int dst_bpp, - int dst_width, int dst_height, unsigned char *dst_data, - int dst_size); - -#endif /* Rgb_H */ diff --git a/nxcomp/Rle.cpp b/nxcomp/Rle.cpp deleted file mode 100644 index 92fc7785a..000000000 --- a/nxcomp/Rle.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "Rle.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -int UnpackRle(T_geometry *geometry, unsigned char method, unsigned char *src_data, - int src_size, int dst_bpp, int dst_width, int dst_height, - unsigned char *dst_data, int dst_size) -{ - if (*src_data == 0) - { - if (dst_size != src_size - 1) - { - #ifdef TEST - *logofs << "UnpackRle: PANIC! Invalid destination size " - << dst_size << " with source " << src_size - << ".\n" << logofs_flush; - #endif - - return -1; - } - - #ifdef TEST - *logofs << "UnpackRle: Expanding " << src_size - 1 - << " bytes of plain RLE data.\n" << logofs_flush; - #endif - - memcpy(dst_data, src_data + 1, src_size - 1); - - return 1; - } - - unsigned int check_size = dst_size; - - int result = ZDecompress(&unpackStream, dst_data, &check_size, - src_data + 1, src_size - 1); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "UnpackRle: PANIC! Failure decompressing RLE data. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decompressing RLE data. " - << "Error is '" << zError(result) << "'.\n"; - - return -1; - } - else if (check_size != (unsigned int) dst_size) - { - #ifdef PANIC - *logofs << "UnpackRle: PANIC! Size mismatch in RLE data. " - << "Resulting size is " << check_size << " with " - << "expected size " << dst_size << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Size mismatch in RLE data. " - << "Resulting size is " << check_size << " with " - << "expected size " << dst_size << ".\n"; - - return -1; - } - - #ifdef TEST - *logofs << "UnpackRle: Decompressed " << src_size - 1 - << " bytes to " << dst_size << " bytes of RLE data.\n" - << logofs_flush; - #endif - - return 1; -} diff --git a/nxcomp/Rle.h b/nxcomp/Rle.h deleted file mode 100644 index cc5dab0e8..000000000 --- a/nxcomp/Rle.h +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Rle_H -#define Rle_H - -#include "Unpack.h" - -int UnpackRle(T_geometry *geometry, unsigned char method, - unsigned char *src_data, int src_size, int dst_bpp, - int dst_width, int dst_height, unsigned char *dst_data, - int dst_size); - -#endif /* Rle_H */ diff --git a/nxcomp/SendEvent.cpp b/nxcomp/SendEvent.cpp deleted file mode 100644 index 8658c1835..000000000 --- a/nxcomp/SendEvent.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "SendEvent.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "IntCache.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int SendEventStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SendEventMessage *sendEvent = (SendEventMessage *) message; - - // - // Here is the fingerprint. - // - - sendEvent -> propagate = *(buffer + 1); - - sendEvent -> window = GetULONG(buffer + 4, bigEndian); - sendEvent -> mask = GetULONG(buffer + 8, bigEndian); - - sendEvent -> code = *(buffer + 12); - sendEvent -> byte_data = *(buffer + 13); - - sendEvent -> sequence = GetUINT(buffer + 14, bigEndian); - - sendEvent -> int_data = GetULONG(buffer + 16, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int SendEventStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SendEventMessage *sendEvent = (SendEventMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = sendEvent -> propagate; - - PutULONG(sendEvent -> window, buffer + 4, bigEndian); - PutULONG(sendEvent -> mask, buffer + 8, bigEndian); - - *(buffer + 12) = sendEvent -> code; - *(buffer + 13) = sendEvent -> byte_data; - - PutUINT(sendEvent -> sequence, buffer + 14, bigEndian); - - PutULONG(sendEvent -> int_data, buffer + 16, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void SendEventStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - SendEventMessage *sendEvent = (SendEventMessage *) message; - - *logofs << name() << ": Identity propagate " << (unsigned int) sendEvent -> propagate - << ", window " << sendEvent -> window << ", mask " << sendEvent -> mask - << ", code " << (unsigned int) sendEvent -> code << ", byte_data " - << (unsigned int) sendEvent -> byte_data << ", sequence " - << sendEvent -> sequence << ", int_data " << sendEvent -> int_data - << ", size " << sendEvent -> size_ << ".\n" << logofs_flush; - - #endif -} - -void SendEventStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ -} - -void SendEventStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - SendEventMessage *sendEvent = (SendEventMessage *) message; - SendEventMessage *cachedSendEvent = (SendEventMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << (unsigned int) sendEvent -> propagate - << " as propagate field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeBoolValue(sendEvent -> propagate); - - cachedSendEvent -> propagate = sendEvent -> propagate; - - #ifdef TEST - *logofs << name() << ": Encoding value " << sendEvent -> window - << " as window field.\n" << logofs_flush; - #endif - - if (sendEvent -> window == 0 || sendEvent -> window == 1) - { - encodeBuffer.encodeBoolValue(1); - - encodeBuffer.encodeBoolValue(sendEvent -> window); - } - else - { - encodeBuffer.encodeBoolValue(0); - - encodeBuffer.encodeXidValue(sendEvent -> window, clientCache -> windowCache); - } - - cachedSendEvent -> window = sendEvent -> window; - - #ifdef TEST - *logofs << name() << ": Encoding value " << sendEvent -> mask - << " as mask field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(sendEvent -> mask, 32, - clientCache -> sendEventMaskCache); - - cachedSendEvent -> mask = sendEvent -> mask; - - #ifdef TEST - *logofs << name() << ": Encoding value " << sendEvent -> code - << " as code field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(sendEvent -> code, 8, - clientCache -> sendEventCodeCache); - - cachedSendEvent -> code = sendEvent -> code; - - #ifdef TEST - *logofs << name() << ": Encoding value " << sendEvent -> byte_data - << " as byte_data field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(sendEvent -> byte_data, 8, - clientCache -> sendEventByteDataCache); - - cachedSendEvent -> byte_data = sendEvent -> byte_data; - - #ifdef TEST - *logofs << name() << ": Encoding value " << sendEvent -> sequence - << " as sequence field.\n" << logofs_flush; - #endif - - unsigned int diffSeq = sendEvent -> sequence - - clientCache -> sendEventLastSequence; - - clientCache -> sendEventLastSequence = sendEvent -> sequence; - - encodeBuffer.encodeValue(diffSeq, 16, 4); - - cachedSendEvent -> sequence = sendEvent -> sequence; - - #ifdef TEST - *logofs << name() << ": Encoding value " << sendEvent -> int_data - << " as int_data field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(sendEvent -> int_data, 32, - clientCache -> sendEventIntDataCache); - - cachedSendEvent -> int_data = sendEvent -> int_data; -} - -void SendEventStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - SendEventMessage *sendEvent = (SendEventMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeBoolValue(value); - - sendEvent -> propagate = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << (unsigned int) sendEvent -> propagate - << " as propagate field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeBoolValue(value); - - if (value) - { - decodeBuffer.decodeBoolValue(value); - } - else - { - decodeBuffer.decodeXidValue(value, clientCache -> windowCache); - } - - sendEvent -> window = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << sendEvent -> window - << " as window field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(sendEvent -> mask, 32, - clientCache -> sendEventMaskCache); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << sendEvent -> mask - << " as mask field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(sendEvent -> code, 8, - clientCache -> sendEventCodeCache); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << sendEvent -> code - << " as code field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(sendEvent -> byte_data, 8, - clientCache -> sendEventByteDataCache); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << sendEvent -> byte_data - << " as byte_data field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeValue(value, 16, 4); - - clientCache -> sendEventLastSequence += value; - clientCache -> sendEventLastSequence &= 0xffff; - - sendEvent -> sequence = clientCache -> sendEventLastSequence; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << sendEvent -> sequence - << " as sequence field.\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(sendEvent -> int_data, 32, - clientCache -> sendEventIntDataCache); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << sendEvent -> int_data - << " as int_data field.\n" << logofs_flush; - #endif -} diff --git a/nxcomp/SendEvent.h b/nxcomp/SendEvent.h deleted file mode 100644 index a8841a706..000000000 --- a/nxcomp/SendEvent.h +++ /dev/null @@ -1,195 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef SendEvent_H -#define SendEvent_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define SENDEVENT_ENABLE_CACHE 1 -#define SENDEVENT_ENABLE_DATA 0 -#define SENDEVENT_ENABLE_SPLIT 0 -#define SENDEVENT_ENABLE_COMPRESS 0 - -#define SENDEVENT_DATA_LIMIT 24 -#define SENDEVENT_DATA_OFFSET 20 - -#define SENDEVENT_CACHE_SLOTS 2000 -#define SENDEVENT_CACHE_THRESHOLD 2 -#define SENDEVENT_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class SendEventMessage : public Message -{ - friend class SendEventStore; - - public: - - SendEventMessage() - { - } - - ~SendEventMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char propagate; - unsigned int window; - unsigned int mask; - - // - // These are part of the event data. - // - - unsigned char code; - unsigned char byte_data; - unsigned short sequence; - unsigned int int_data; -}; - -class SendEventStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - SendEventStore() : MessageStore() - { - enableCache = SENDEVENT_ENABLE_CACHE; - enableData = SENDEVENT_ENABLE_DATA; - enableSplit = SENDEVENT_ENABLE_SPLIT; - enableCompress = SENDEVENT_ENABLE_COMPRESS; - - dataLimit = SENDEVENT_DATA_LIMIT; - dataOffset = SENDEVENT_DATA_OFFSET; - - cacheSlots = SENDEVENT_CACHE_SLOTS; - cacheThreshold = SENDEVENT_CACHE_THRESHOLD; - cacheLowerThreshold = SENDEVENT_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~SendEventStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "SendEvent"; - } - - virtual unsigned char opcode() const - { - return X_SendEvent; - } - - virtual unsigned int storage() const - { - return sizeof(SendEventMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new SendEventMessage(); - } - - virtual Message *create(const Message &message) const - { - return new SendEventMessage((const SendEventMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (SendEventMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* SendEvent_H */ diff --git a/nxcomp/SequenceQueue.cpp b/nxcomp/SequenceQueue.cpp deleted file mode 100644 index 3114bfcd0..000000000 --- a/nxcomp/SequenceQueue.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "SequenceQueue.h" - -static const unsigned int INITIAL_SIZE_ = 16; -static const unsigned int GROWTH_INCREMENT = 16; - -SequenceQueue::SequenceQueue() - - : queue_(new RequestSequence[INITIAL_SIZE_]), size_(INITIAL_SIZE_), - length_(0), start_(0), end_(0) -{ -} - -SequenceQueue::~SequenceQueue() -{ - delete [] queue_; -} - -void SequenceQueue::push(unsigned short int sequence, unsigned char opcode, - unsigned int data1, unsigned int data2, - unsigned int data3) -{ - if (length_ == 0) - { - start_ = end_ = 0; - - queue_[0].opcode = opcode; - queue_[0].sequence = sequence; - - queue_[0].data1 = data1; - queue_[0].data2 = data2; - queue_[0].data3 = data3; - - length_ = 1; - - return; - } - - if (length_ == size_) - { - size_ += GROWTH_INCREMENT; - - RequestSequence *newQueue = new RequestSequence[size_]; - - for (int i = start_; (unsigned int) i < length_; i++) - { - newQueue[i - start_] = queue_[i]; - } - - for (int i1 = 0; (unsigned int) i1 < start_; i1++) - { - newQueue[i1 + length_ - start_] = queue_[i1]; - } - - delete [] queue_; - - queue_ = newQueue; - - start_ = 0; - - end_ = length_ - 1; - } - - end_++; - - if (end_ == size_) - { - end_ = 0; - } - - queue_[end_].opcode = opcode; - queue_[end_].sequence = sequence; - - queue_[end_].data1 = data1; - queue_[end_].data2 = data2; - queue_[end_].data3 = data3; - - length_++; -} - -int SequenceQueue::peek(unsigned short int &sequence, - unsigned char &opcode) -{ - if (length_ == 0) - { - return 0; - } - else - { - opcode = queue_[start_].opcode; - sequence = queue_[start_].sequence; - - return 1; - } -} - -int SequenceQueue::peek(unsigned short int &sequence, unsigned char &opcode, - unsigned int &data1, unsigned int &data2, - unsigned int &data3) -{ - if (length_ == 0) - { - return 0; - } - else - { - opcode = queue_[start_].opcode; - sequence = queue_[start_].sequence; - - data1 = queue_[start_].data1; - data2 = queue_[start_].data2; - data3 = queue_[start_].data3; - - return 1; - } -} - -int SequenceQueue::pop(unsigned short int &sequence, unsigned char &opcode, - unsigned int &data1, unsigned int &data2, - unsigned int &data3) -{ - if (length_ == 0) - { - return 0; - } - else - { - opcode = queue_[start_].opcode; - sequence = queue_[start_].sequence; - - data1 = queue_[start_].data1; - data2 = queue_[start_].data2; - data3 = queue_[start_].data3; - - start_++; - - if (start_ == size_) - { - start_ = 0; - } - - length_--; - - return 1; - } -} diff --git a/nxcomp/SequenceQueue.h b/nxcomp/SequenceQueue.h deleted file mode 100644 index 2a72bc3fe..000000000 --- a/nxcomp/SequenceQueue.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef SequenceQueue_H -#define SequenceQueue_H - -// -// List of outstanding request messages which -// are waiting for a reply. This class is used -// in X client and server channels to correlate -// the replies sequence numbers to the original -// request type. -// - -class SequenceQueue -{ - public: - - SequenceQueue(); - - virtual ~SequenceQueue(); - - void push(unsigned short int sequence, unsigned char opcode, - unsigned int data1 = 0, unsigned int data2 = 0, - unsigned int data3 = 0); - - int peek(unsigned short int &sequence, unsigned char &opcode); - - int peek(unsigned short int &sequence, unsigned char &opcode, - unsigned int &data1, unsigned int &data2, - unsigned int &data3); - - int pop(unsigned short int &sequence, unsigned char &opcode, - unsigned int &data1, unsigned int &data2, - unsigned int &data3); - - int pop(unsigned short int &sequence, unsigned char &opcode) - { - unsigned int data1, data2, data3; - - return pop(sequence, opcode, data1, data2, data3); - } - - int length() - { - return length_; - } - - private: - - struct RequestSequence - { - unsigned short int sequence; - unsigned char opcode; - unsigned int data1; - unsigned int data2; - unsigned int data3; - }; - - RequestSequence *queue_; - - unsigned int size_; - unsigned int length_; - - unsigned int start_; - unsigned int end_; -}; - -#endif /* SequenceQueue_H */ diff --git a/nxcomp/ServerCache.cpp b/nxcomp/ServerCache.cpp deleted file mode 100644 index 00693d2af..000000000 --- a/nxcomp/ServerCache.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ServerCache.h" - -// -// Some global caches used to store information -// common to all X connections. -// - -BlockCache ServerCache::lastInitReply; -BlockCache ServerCache::lastKeymap; -unsigned char ServerCache::getKeyboardMappingLastKeysymsPerKeycode = 0; -BlockCache ServerCache::getKeyboardMappingLastMap; -BlockCache ServerCache::getModifierMappingLastMap; -BlockCache ServerCache::xResources; -BlockCacheSet ServerCache::queryFontFontCache(16); - -ServerCache::ServerCache() : - - replySequenceCache(6), eventSequenceCache(6), - lastTimestamp(0), visualCache(8), colormapCache(8), - - errorMinorCache(8), - - colormapNotifyWindowCache(8), colormapNotifyColormapCache(8), - - createNotifyWindowCache(8), createNotifyLastWindow(0), - - exposeWindowCache(12), - - focusInWindowCache(8), - - keyPressLastKey(0), - - mapNotifyEventCache(8), mapNotifyWindowCache(8), - - motionNotifyTimestampCache(8), motionNotifyLastRootX(0), - motionNotifyLastRootY(0), motionNotifyRootXCache(8), - motionNotifyRootYCache(8), motionNotifyEventXCache(8), - motionNotifyEventYCache(8), motionNotifyStateCache(8), - - noExposeDrawableCache(8), noExposeMinorCache(8), - - propertyNotifyWindowCache(8), propertyNotifyAtomCache(8), - - reparentNotifyWindowCache(8), - - selectionClearWindowCache(8), selectionClearAtomCache(8), - - visibilityNotifyWindowCache(8), - - getGeometryRootCache(8), - - getInputFocusWindowCache(8), - - getKeyboardMappingKeysymCache(8), - - getPropertyTypeCache(8), - - getSelectionOwnerCache(8), - - getWindowAttributesClassCache(8), getWindowAttributesPlanesCache(8), - getWindowAttributesPixelCache(8), getWindowAttributesAllEventsCache(8), - getWindowAttributesYourEventsCache(8), - getWindowAttributesDontPropagateCache(8), - - queryPointerRootCache(8), queryPointerChildCache(8), - - translateCoordsChildCache(8), translateCoordsXCache(8), - translateCoordsYCache(8), - - queryTreeWindowCache(8) - -{ - unsigned int i; - - for (i = 0; i < 3; i++) - { - configureNotifyWindowCache[i] = new IntCache(8); - } - - for (i = 0; i < 5; i++) - { - configureNotifyGeomCache[i] = new IntCache(8); - } - - for (i = 0; i < 5; i++) - { - exposeGeomCache[i] = new IntCache(8); - } - - for (i = 0; i < 3; i++) - { - motionNotifyWindowCache[i] = new IntCache(8); - } - - for (i = 0; i < 5; i++) - { - getGeometryGeomCache[i] = new IntCache(8); - } - - for (i = 0; i < 23; i++) - { - keyPressCache[i] = 0; - } - - for (i = 0; i < 6; i++) - { - queryFontCharInfoCache[i] = new IntCache(8); - queryFontLastCharInfo[i] = 0; - } - - for (i = 0; i < 12; i++) - { - genericReplyIntCache[i] = new IntCache(8); - } - - for (i = 0; i < 14; i++) - { - genericEventIntCache[i] = new IntCache(8); - } -} - - -ServerCache::~ServerCache() -{ - unsigned int i; - - for (i = 0; i < 3; i++) - { - delete configureNotifyWindowCache[i]; - } - - for (i = 0; i < 5; i++) - { - delete configureNotifyGeomCache[i]; - } - - for (i = 0; i < 5; i++) - { - delete exposeGeomCache[i]; - } - - for (i = 0; i < 3; i++) - { - delete motionNotifyWindowCache[i]; - } - - for (i = 0; i < 5; i++) - { - delete getGeometryGeomCache[i]; - } - - for (i = 0; i < 6; i++) - { - delete queryFontCharInfoCache[i]; - } - - for (i = 0; i < 12; i++) - { - delete genericReplyIntCache[i]; - } - - for (i = 0; i < 14; i++) - { - delete genericEventIntCache[i]; - } -} diff --git a/nxcomp/ServerCache.h b/nxcomp/ServerCache.h deleted file mode 100644 index c6e2b81b6..000000000 --- a/nxcomp/ServerCache.h +++ /dev/null @@ -1,303 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ServerCache_H -#define ServerCache_H - -#include "Misc.h" - -#include "IntCache.h" -#include "CharCache.h" -#include "OpcodeCache.h" -#include "BlockCache.h" -#include "BlockCacheSet.h" - -#include "ChannelCache.h" - -class ServerCache : public ChannelCache -{ - public: - - ServerCache(); - - ~ServerCache(); - - // - // Opcode prediction caches. - // - - OpcodeCache opcodeCache; - - // - // General-purpose caches. - // - - IntCache replySequenceCache; - IntCache eventSequenceCache; - unsigned int lastTimestamp; - CharCache depthCache; - IntCache visualCache; - IntCache colormapCache; - CharCache resourceCache; - - // - // X connection startup. - // - - static BlockCache lastInitReply; - - // - // X errors. - // - - CharCache errorCodeCache; - IntCache errorMinorCache; - CharCache errorMajorCache; - - // - // ButtonPress and ButtonRelease events. - // - - CharCache buttonCache; - - // - // ColormapNotify event. - // - - IntCache colormapNotifyWindowCache; - IntCache colormapNotifyColormapCache; - - // - // ConfigureNotify event. - // - - IntCache *configureNotifyWindowCache[3]; - IntCache *configureNotifyGeomCache[5]; - - // - // CreateNotify event. - // - - IntCache createNotifyWindowCache; - unsigned int createNotifyLastWindow; - - // - // Expose event. - // - - IntCache exposeWindowCache; - IntCache *exposeGeomCache[5]; - - // - // FocusIn event (also used for FocusOut). - // - - IntCache focusInWindowCache; - - // - // KeymapNotify event. - // - - static BlockCache lastKeymap; - - // - // KeyPress event. - // - - unsigned char keyPressLastKey; - unsigned char keyPressCache[23]; - - // - // MapNotify event (also used for UnmapNotify). - // - - IntCache mapNotifyEventCache; - IntCache mapNotifyWindowCache; - - // - // MotionNotify event (also used for KeyPress, - // KeyRelease, ButtonPress, ButtonRelease, - // EnterNotify, and LeaveNotify events and - // QueryPointer reply). - // - - IntCache motionNotifyTimestampCache; - unsigned int motionNotifyLastRootX; - unsigned int motionNotifyLastRootY; - IntCache motionNotifyRootXCache; - IntCache motionNotifyRootYCache; - IntCache motionNotifyEventXCache; - IntCache motionNotifyEventYCache; - IntCache motionNotifyStateCache; - IntCache *motionNotifyWindowCache[3]; - - // - // NoExpose event. - // - - IntCache noExposeDrawableCache; - IntCache noExposeMinorCache; - CharCache noExposeMajorCache; - - // - // PropertyNotify event. - // - - IntCache propertyNotifyWindowCache; - IntCache propertyNotifyAtomCache; - - // - // ReparentNotify event. - // - - IntCache reparentNotifyWindowCache; - - // - // SelectionClear event. - // - - IntCache selectionClearWindowCache; - IntCache selectionClearAtomCache; - - // - // VisibilityNotify event. - // - - IntCache visibilityNotifyWindowCache; - - // - // GetGeometry reply. - // - - IntCache getGeometryRootCache; - IntCache *getGeometryGeomCache[5]; - - // - // GetInputFocus reply. - // - - IntCache getInputFocusWindowCache; - - // - // GetKeyboardMapping reply. - // - - static unsigned char getKeyboardMappingLastKeysymsPerKeycode; - static BlockCache getKeyboardMappingLastMap; - IntCache getKeyboardMappingKeysymCache; - CharCache getKeyboardMappingLastByteCache; - - // - // GetModifierMapping reply. - // - - static BlockCache getModifierMappingLastMap; - - // - // GetProperty reply. - // - - CharCache getPropertyFormatCache; - IntCache getPropertyTypeCache; - static BlockCache xResources; - - // - // GetSelection reply. - // - - IntCache getSelectionOwnerCache; - - // - // GetWindowAttributes reply. - // - - IntCache getWindowAttributesClassCache; - CharCache getWindowAttributesBitGravityCache; - CharCache getWindowAttributesWinGravityCache; - IntCache getWindowAttributesPlanesCache; - IntCache getWindowAttributesPixelCache; - IntCache getWindowAttributesAllEventsCache; - IntCache getWindowAttributesYourEventsCache; - IntCache getWindowAttributesDontPropagateCache; - - // - // QueryColors reply. - // - - BlockCache queryColorsLastReply; - - // - // QueryFont reply. - // - - static BlockCacheSet queryFontFontCache; - IntCache *queryFontCharInfoCache[6]; - unsigned int queryFontLastCharInfo[6]; - - // - // QueryPointer reply. - // - - IntCache queryPointerRootCache; - IntCache queryPointerChildCache; - - // - // TranslateCoords reply. - // - - IntCache translateCoordsChildCache; - IntCache translateCoordsXCache; - IntCache translateCoordsYCache; - - // - // QueryTree reply. - // - - IntCache queryTreeWindowCache; - - // - // Generic reply. Use short data - // in protocol versions >= 3. - // - - CharCache genericReplyCharCache; - IntCache *genericReplyIntCache[12]; - - // - // Generic event. Only in protocol - // versions >= 3. - // - - CharCache genericEventCharCache; - IntCache *genericEventIntCache[14]; - - // - // Used in the abort split events. - // - - OpcodeCache abortOpcodeCache; -}; - -#endif /* ServerCache_H */ diff --git a/nxcomp/ServerChannel.cpp b/nxcomp/ServerChannel.cpp deleted file mode 100644 index eff24e90e..000000000 --- a/nxcomp/ServerChannel.cpp +++ /dev/null @@ -1,7942 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#ifndef ANDROID -#include -#endif - -#include -#include - -#include "NXproto.h" -#include "NXalert.h" -#include "NXpack.h" -#include "NXmitshm.h" - -#include "ServerChannel.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "StaticCompressor.h" - -#include "Statistics.h" -#include "Proxy.h" - -#include "Auth.h" -#include "Unpack.h" - -// -// Available unpack methods. -// - -#include "Alpha.h" -#include "Colormap.h" -#include "Bitmap.h" -#include "Jpeg.h" -#include "Pgn.h" -#include "Rgb.h" -#include "Rle.h" - -extern Proxy *proxy; - -// -// Set the verbosity level. You also -// need to define OPCODES in Misc.cpp -// if you want literals instead of -// opcodes' numbers. -// - -#define PANIC -#define WARNING -#undef OPCODES -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Log the important tracepoints related -// to writing packets to the peer proxy. -// - -#undef FLUSH - -// -// Log the operations related to splits. -// - -#undef SPLIT - -// -// Define this to log when a channel -// is created or destroyed. -// - -#undef REFERENCES - -// -// Define this to exit and suspend the -// session after a given number of X -// messages decoded by the proxy. -// - -#undef SUSPEND - -// -// Define these to hide the server extensions. -// - -#define HIDE_MIT_SHM_EXTENSION -#define HIDE_BIG_REQUESTS_EXTENSION -#define HIDE_XFree86_Bigfont_EXTENSION -#undef HIDE_SHAPE_EXTENSION -#undef HIDE_XKEYBOARD_EXTENSION - -// -// Known reasons of connection failures. -// - -#define INVALID_COOKIE_DATA "Invalid MIT-MAGIC-COOKIE-1 key" -#define INVALID_COOKIE_SIZE ((int) sizeof(INVALID_COOKIE_DATA) - 1) - -#define NO_AUTH_PROTO_DATA "No protocol specified" -#define NO_AUTH_PROTO_SIZE ((int) sizeof(NO_AUTH_PROTO_DATA) - 1) - -// -// Here are the static members. -// - -#ifdef REFERENCES - -int ServerChannel::references_ = 0; - -#endif - -ServerChannel::ServerChannel(Transport *transport, StaticCompressor *compressor) - - : Channel(transport, compressor), readBuffer_(transport_, this) -{ - // - // Sequence number of the next message - // being encoded or decoded. - // - - clientSequence_ = 0; - serverSequence_ = 0; - - // - // Save the last motion event and flush - // it only when the timeout expires. - // - - lastMotion_[0] = '\0'; - - // - // Clear the queue of sequence numbers - // of split commits. Used to mask the - // errors. - // - - initCommitQueue(); - - // - // Do we enable or not sending of expose - // events to the X client. - // - - enableExpose_ = 1; - enableGraphicsExpose_ = 1; - enableNoExpose_ = 1; - - // - // Track data of image currently being - // decompressed. - // - - imageState_ = NULL; - - // - // Track MIT-SHM resources. - // - - shmemState_ = NULL; - - // - // Store the unpack state for each agent - // resource. - // - - for (int i = 0; i < CONNECTIONS_LIMIT; i++) - { - unpackState_[i] = NULL; - } - - // - // Data about the split parameters requested - // by the encoding side. - // - - splitState_.resource = nothing; - splitState_.current = 0; - splitState_.save = 1; - splitState_.load = 1; - splitState_.commit = 0; - - // - // It will be eventually set by - // the server proxy. - // - - fontPort_ = -1; - - #ifdef REFERENCES - *logofs << "ServerChannel: Created new object at " - << this << " for FD#" << fd_ << " out of " - << ++references_ << " allocated channels.\n" - << logofs_flush; - #endif -} - -ServerChannel::~ServerChannel() -{ - #ifdef TEST - *logofs << "ServerChannel: Freeing image state information.\n" - << logofs_flush; - #endif - - handleImageStateRemove(); - - #ifdef TEST - *logofs << "ServerChannel: Freeing shared memory information.\n" - << logofs_flush; - #endif - - handleShmemStateRemove(); - - #ifdef TEST - *logofs << "ServerChannel: Freeing unpack state information.\n" - << logofs_flush; - #endif - - for (int i = 0; i < CONNECTIONS_LIMIT; i++) - { - handleUnpackStateRemove(i); - } - - #ifdef TEST - *logofs << "ServerChannel: Freeing channel caches.\n" - << logofs_flush; - #endif - - #ifdef REFERENCES - *logofs << "ServerChannel: Deleted object at " - << this << " for FD#" << fd_ << " out of " - << --references_ << " allocated channels.\n" - << logofs_flush; - #endif -} - -// -// Beginning of handleRead(). -// - -int ServerChannel::handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, - unsigned int length) -{ - #ifdef DEBUG - *logofs << "handleRead: Called for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - // - // Pointer to located message and - // its size in bytes. - // - - const unsigned char *inputMessage; - unsigned int inputLength; - - // - // Set when message is found in - // cache. - // - - int hit; - - #if defined(TEST) || defined(INFO) - *logofs << "handleRead: Trying to read from FD#" - << fd_ << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - int result = readBuffer_.readMessage(); - - #if defined(DEBUG) || defined(INFO) - *logofs << "handleRead: Read result on FD#" << fd_ - << " is " << result << ".\n" - << logofs_flush; - #endif - - if (result < 0) - { - // - // Let the proxy close the channel. - // - - return -1; - } - else if (result == 0) - { - #if defined(TEST) || defined(INFO) - - // - // This can happen because we have the descriptor - // selected in the read set but we already read - // the data asynchronously, while decoding data - // read from the proxy. - // - - *logofs << "handleRead: WARNING! No data read from FD#" - << fd_ << " while encoding messages.\n" - << logofs_flush; - - #endif - - return 0; - } - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "handleRead: Encoding messages for FD#" << fd_ - << " with " << readBuffer_.getLength() << " bytes " - << "in the buffer.\n" << logofs_flush; - #endif - - // - // Extract any complete message which - // is available in the buffer. - // - - if (proxy -> handleAsyncSwitch(fd_) < 0) - { - return -1; - } - - while ((inputMessage = readBuffer_.getMessage(inputLength)) != NULL) - { - hit = 0; - - if (firstReply_) - { - // - // Handle the X server's authorization reply. - // - - if (handleAuthorization(inputMessage, inputLength) < 0) - { - return -1; - } - - imageByteOrder_ = inputMessage[30]; - bitmapBitOrder_ = inputMessage[31]; - scanlineUnit_ = inputMessage[32]; - scanlinePad_ = inputMessage[33]; - - encodeBuffer.encodeValue((unsigned int) inputMessage[0], 8); - encodeBuffer.encodeValue((unsigned int) inputMessage[1], 8); - encodeBuffer.encodeValue(GetUINT(inputMessage + 2, bigEndian_), 16); - encodeBuffer.encodeValue(GetUINT(inputMessage + 4, bigEndian_), 16); - encodeBuffer.encodeValue(GetUINT(inputMessage + 6, bigEndian_), 16); - - if (ServerCache::lastInitReply.compare(inputLength - 8, inputMessage + 8)) - { - encodeBuffer.encodeBoolValue(1); - } - else - { - encodeBuffer.encodeBoolValue(0); - - for (unsigned int i = 8; i < inputLength; i++) - { - encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8); - } - } - - firstReply_ = 0; - - #if defined(TEST) || defined(OPCODES) - - int bits = encodeBuffer.diffBits(); - - *logofs << "handleRead: Handled first reply. " << inputLength - << " bytes in, " << bits << " bits (" << ((float) bits) / 8 - << " bytes) out.\n" << logofs_flush; - - #endif - - priority_++; - - } - else - { - // - // NX client needs this line to consider - // the initialization phase successfully - // completed. - // - - if (firstClient_ == -1) - { - cerr << "Info" << ": Established X server connection.\n" ; - - firstClient_ = fd_; - } - - // - // Check if this is a reply. - // - - if (*inputMessage == X_Reply) - { - int bits = 0; - - unsigned char inputOpcode = *inputMessage; - - unsigned short int requestSequenceNum; - unsigned char requestOpcode; - unsigned int requestData[3]; - - unsigned int sequenceNum = GetUINT(inputMessage + 2, bigEndian_); - - #ifdef SUSPEND - - if (sequenceNum >= 1000) - { - cerr << "Warning" << ": Exiting to test the resilience of the agent.\n"; - - sleep(2); - - HandleAbort(); - } - - #endif - - // - // We managed all the events and errors caused - // by the previous requests. We can now reset - // the queue of split commits. - // - - clearCommitQueue(); - - // - // Encode opcode and difference between - // current sequence and the last one. - // - - encodeBuffer.encodeOpcodeValue(inputOpcode, serverCache_ -> opcodeCache); - - unsigned int sequenceDiff = sequenceNum - serverSequence_; - - serverSequence_ = sequenceNum; - - #ifdef DEBUG - *logofs << "handleRead: Last server sequence number for FD#" - << fd_ << " is " << serverSequence_ << " with " - << "difference " << sequenceDiff << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(sequenceDiff, 16, - serverCache_ -> replySequenceCache, 7); - - // - // Now handle the data part. - // - - if (sequenceQueue_.peek(requestSequenceNum, requestOpcode) && - requestSequenceNum == sequenceNum) - { - // - // We've found the request that generated this reply. - // It is possible to compress the reply based on the - // specific request type. - // - - sequenceQueue_.pop(requestSequenceNum, requestOpcode, - requestData[0], requestData[1], requestData[2]); - - // - // If differential compression is disabled - // then use the most simple encoding. - // - - if (control -> LocalDeltaCompression == 0) - { - int result = handleFastReadReply(encodeBuffer, requestOpcode, - inputMessage, inputLength); - if (result < 0) - { - return -1; - } - else if (result > 0) - { - continue; - } - } - - switch (requestOpcode) - { - case X_AllocColor: - { - const unsigned char *nextSrc = inputMessage + 8; - for (unsigned int i = 0; i < 3; i++) - { - unsigned int colorValue = GetUINT(nextSrc, bigEndian_); - nextSrc += 2; - if (colorValue == requestData[i]) - encodeBuffer.encodeBoolValue(1); - else - { - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeValue(colorValue - colorValue, 16, 6); - } - } - unsigned int pixel = GetULONG(inputMessage + 16, bigEndian_); - encodeBuffer.encodeValue(pixel, 32, 9); - - priority_++; - } - break; - case X_GetAtomName: - { - unsigned int nameLength = GetUINT(inputMessage + 8, bigEndian_); - encodeBuffer.encodeValue(nameLength, 16, 6); - const unsigned char *nextSrc = inputMessage + 32; - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, nameLength); - - priority_++; - } - break; - case X_GetGeometry: - { - // - // TODO: This obtains a satisfactory 10:1, but - // could be cached to leverage the big amount - // of such requests issued by QT clients. - // - - encodeBuffer.encodeCachedValue(inputMessage[1], 8, - serverCache_ -> depthCache); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> getGeometryRootCache, 9); - const unsigned char *nextSrc = inputMessage + 12; - for (unsigned int i = 0; i < 5; i++) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *serverCache_ -> getGeometryGeomCache[i], 8); - nextSrc += 2; - } - - priority_++; - } - break; - case X_GetInputFocus: - { - // - // Is it a real X_GetInputFocus or a - // masqueraded reply? - // - - if (requestData[0] == X_GetInputFocus) - { - encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> getInputFocusWindowCache); - - priority_++; - } - else - { - // - // TODO: We are not setting priority in case - // of replies other than real X_GetInputFocus - // or X_NXGetUnpackParameters. We should check - // once again that this is OK. - // - - #ifdef TEST - *logofs << "handleRead: Received tainted X_GetInputFocus reply " - << "for request OPCODE#" << requestData[0] << " with " - << "sequence " << sequenceNum << ".\n" - << logofs_flush; - #endif - - // - // Don't encode any data in case of sync - // messages or any other reply for which - // opcode is enough. - // - - if (requestData[0] == opcodeStore_ -> getUnpackParameters) - { - for (int i = 0; i < PACK_METHOD_LIMIT; i++) - { - encodeBuffer.encodeBoolValue(control -> LocalUnpackMethods[i]); - } - - priority_++; - } - else if (requestData[0] == opcodeStore_ -> getShmemParameters) - { - if (handleShmemReply(encodeBuffer, requestOpcode, requestData[1], - inputMessage, inputLength) < 0) - { - return -1; - } - - priority_++; - } - else if (requestData[0] == opcodeStore_ -> getFontParameters) - { - if (handleFontReply(encodeBuffer, requestOpcode, - inputMessage, inputLength) < 0) - { - return -1; - } - } - - // - // Account this data to the original opcode. - // - - requestOpcode = requestData[0]; - } - } - break; - case X_GetKeyboardMapping: - { - unsigned int keysymsPerKeycode = (unsigned int) inputMessage[1]; - if (ServerCache::getKeyboardMappingLastMap.compare(inputLength - 32, - inputMessage + 32) && (keysymsPerKeycode == - ServerCache::getKeyboardMappingLastKeysymsPerKeycode)) - { - encodeBuffer.encodeBoolValue(1); - - priority_++; - - break; - } - ServerCache::getKeyboardMappingLastKeysymsPerKeycode = keysymsPerKeycode; - encodeBuffer.encodeBoolValue(0); - unsigned int numKeycodes = - (((inputLength - 32) / keysymsPerKeycode) >> 2); - encodeBuffer.encodeValue(numKeycodes, 8); - encodeBuffer.encodeValue(keysymsPerKeycode, 8, 4); - const unsigned char *nextSrc = inputMessage + 32; - unsigned char previous = 0; - for (unsigned int count = numKeycodes * keysymsPerKeycode; - count; --count) - { - unsigned int keysym = GetULONG(nextSrc, bigEndian_); - nextSrc += 4; - if (keysym == NoSymbol) - encodeBuffer.encodeBoolValue(1); - else - { - encodeBuffer.encodeBoolValue(0); - unsigned int first3Bytes = (keysym >> 8); - encodeBuffer.encodeCachedValue(first3Bytes, 24, - serverCache_ -> getKeyboardMappingKeysymCache, 9); - unsigned char lastByte = (unsigned char) (keysym & 0xff); - encodeBuffer.encodeCachedValue(lastByte - previous, 8, - serverCache_ -> getKeyboardMappingLastByteCache, 5); - previous = lastByte; - } - } - - priority_++; - } - break; - case X_GetModifierMapping: - { - encodeBuffer.encodeValue((unsigned int) inputMessage[1], 8); - const unsigned char *nextDest = inputMessage + 32; - if (ServerCache::getModifierMappingLastMap.compare(inputLength - 32, - nextDest)) - { - encodeBuffer.encodeBoolValue(1); - - priority_++; - - break; - } - encodeBuffer.encodeBoolValue(0); - for (unsigned int count = inputLength - 32; count; count--) - { - unsigned char next = *nextDest++; - if (next == 0) - encodeBuffer.encodeBoolValue(1); - else - { - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeValue(next, 8); - } - } - - priority_++; - } - break; - case X_GetProperty: - { - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_GetProperty); - - hit = handleEncode(encodeBuffer, serverCache_, messageStore, - requestOpcode, inputMessage, inputLength); - - priority_++; - } - break; - case X_GetSelectionOwner: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> getSelectionOwnerCache, 9); - priority_++; - } - break; - case X_GetWindowAttributes: - { - encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> visualCache); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 12, bigEndian_), - 16, serverCache_ -> getWindowAttributesClassCache, 3); - encodeBuffer.encodeCachedValue(inputMessage[14], 8, - serverCache_ -> getWindowAttributesBitGravityCache); - encodeBuffer.encodeCachedValue(inputMessage[15], 8, - serverCache_ -> getWindowAttributesWinGravityCache); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), - 32, serverCache_ -> getWindowAttributesPlanesCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 20, bigEndian_), - 32, serverCache_ -> getWindowAttributesPixelCache, 9); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[24]); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[25]); - encodeBuffer.encodeValue((unsigned int) inputMessage[26], 2); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[27]); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 28, bigEndian_), - 29, serverCache_ -> colormapCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 32, bigEndian_), - 32, serverCache_ -> getWindowAttributesAllEventsCache); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 36, bigEndian_), - 32, serverCache_ -> getWindowAttributesYourEventsCache); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 40, bigEndian_), - 16, serverCache_ -> getWindowAttributesDontPropagateCache); - - priority_++; - } - break; - case X_GrabKeyboard: - case X_GrabPointer: - { - encodeBuffer.encodeValue((unsigned int) inputMessage[1], 3); - - priority_++; - } - break; - case X_InternAtom: - { - encodeBuffer.encodeValue(GetULONG(inputMessage + 8, bigEndian_), 29, 9); - - priority_++; - } - break; - case X_ListExtensions: - { - encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 8); - unsigned int numExtensions = (unsigned int) inputMessage[1]; - encodeBuffer.encodeValue(numExtensions, 8); - const unsigned char *nextSrc = inputMessage + 32; - - for (; numExtensions; numExtensions--) - { - unsigned int length = (unsigned int) (*nextSrc++); - - encodeBuffer.encodeValue(length, 8); - - #ifdef HIDE_MIT_SHM_EXTENSION - - if (!strncmp((char *) nextSrc, "MIT-SHM", 7)) - { - #ifdef TEST - *logofs << "handleRead: Hiding MIT-SHM extension in reply.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) nextSrc, "NO-MIT-", 7); - } - - #endif - - #ifdef HIDE_BIG_REQUESTS_EXTENSION - - if (!strncmp((char *) nextSrc, "BIG-REQUESTS", 12)) - { - #ifdef TEST - *logofs << "handleRead: Hiding BIG-REQUESTS extension in reply.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) nextSrc, "NO-BIG-REQUE", 12); - } - - #endif - - #ifdef HIDE_XKEYBOARD_EXTENSION - - if (!strncmp((char *) nextSrc, "XKEYBOARD", 9)) - { - #ifdef TEST - *logofs << "handleRead: Hiding XKEYBOARD extension in reply.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) nextSrc, "NO-XKEYBO", 9); - } - - #endif - - #ifdef HIDE_XFree86_Bigfont_EXTENSION - - if (!strncmp((char *) nextSrc, "XFree86-Bigfont", 15)) - { - #ifdef TEST - *logofs << "handleRead: Hiding XFree86-Bigfont extension in reply.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) nextSrc, "NO-XFree86-Bigf", 15); - } - - #endif - - #ifdef HIDE_SHAPE_EXTENSION - - if (!strncmp((char *) nextSrc, "SHAPE", 5)) - { - #ifdef TEST - *logofs << "handleRead: Hiding SHAPE extension in reply.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) nextSrc, "NO-SH", 5); - } - - #endif - - // - // Check if user disabled RENDER extension. - // - - if (control -> HideRender == 1 && - !strncmp((char *) nextSrc, "RENDER", 6)) - { - #ifdef TEST - *logofs << "handleRead: Hiding RENDER extension in reply.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) nextSrc, "NO-REN", 6); - } - - for (; length; length--) - { - encodeBuffer.encodeValue((unsigned int) (*nextSrc++), 8); - } - } - - priority_++; - } - break; - case X_ListFonts: - { - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_ListFonts); - - if (handleEncodeCached(encodeBuffer, serverCache_, messageStore, - inputMessage, inputLength)) - { - priority_++; - - hit = 1; - - break; - } - - encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 8); - unsigned int numFonts = GetUINT(inputMessage + 8, bigEndian_); - encodeBuffer.encodeValue(numFonts, 16, 6); - - // Differential encoding. - encodeBuffer.encodeBoolValue(1); - - const unsigned char* nextSrc = inputMessage + 32; - for (; numFonts; numFonts--) - { - unsigned int length = (unsigned int) (*nextSrc++); - encodeBuffer.encodeValue(length, 8); - - // Since ProtoStep7 (#issue 108) - encodeBuffer.encodeTextData(nextSrc, length); - - nextSrc += length; - } - - priority_++; - } - break; - case X_LookupColor: - case X_AllocNamedColor: - { - const unsigned char *nextSrc = inputMessage + 8; - if (requestOpcode == X_AllocNamedColor) - { - encodeBuffer.encodeValue(GetULONG(nextSrc, bigEndian_), 32, 9); - nextSrc += 4; - } - unsigned int count = 3; - do - { - unsigned int exactColor = GetUINT(nextSrc, bigEndian_); - encodeBuffer.encodeValue(exactColor, 16, 9); - unsigned int visualColor = GetUINT(nextSrc + 6, bigEndian_) - - exactColor; - encodeBuffer.encodeValue(visualColor, 16, 5); - nextSrc += 2; - } - while (--count); - - priority_++; - } - break; - case X_QueryBestSize: - { - encodeBuffer.encodeValue(GetUINT(inputMessage + 8, bigEndian_), 16, 8); - encodeBuffer.encodeValue(GetUINT(inputMessage + 10, bigEndian_), 16, 8); - - priority_++; - } - break; - case X_QueryColors: - { - // Differential encoding. - encodeBuffer.encodeBoolValue(1); - - unsigned int numColors = ((inputLength - 32) >> 3); - const unsigned char *nextSrc = inputMessage + 40; - unsigned char *nextDest = (unsigned char *) inputMessage + 38; - for (unsigned int c = 1; c < numColors; c++) - { - for (unsigned int i = 0; i < 6; i++) - *nextDest++ = *nextSrc++; - nextSrc += 2; - } - unsigned int colorsLength = numColors * 6; - if (serverCache_ -> queryColorsLastReply.compare(colorsLength, - inputMessage + 32)) - encodeBuffer.encodeBoolValue(1); - else - { - const unsigned char *nextSrc = inputMessage + 32; - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeValue(numColors, 16, 5); - for (numColors *= 3; numColors; numColors--) - { - encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16); - nextSrc += 2; - } - } - - priority_++; - } - break; - case X_QueryExtension: - { - if (requestData[0] == X_QueryExtension) - { - // - // Value in requestData[0] will be nonzero - // if the request is for an extension that - // we should hide to the X client. - // - - if (requestData[1]) - { - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeValue(0, 8); - } - else - { - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[8]); - encodeBuffer.encodeValue((unsigned int) inputMessage[9], 8); - } - - encodeBuffer.encodeValue((unsigned int) inputMessage[10], 8); - encodeBuffer.encodeValue((unsigned int) inputMessage[11], 8); - - if (requestData[2] == X_NXInternalShapeExtension) - { - opcodeStore_ -> shapeExtension = inputMessage[9]; - - #ifdef TEST - *logofs << "handleRead: Shape extension opcode for FD#" << fd_ - << " is " << (unsigned int) opcodeStore_ -> shapeExtension - << ".\n" << logofs_flush; - #endif - } - else if (requestData[2] == X_NXInternalRenderExtension) - { - opcodeStore_ -> renderExtension = inputMessage[9]; - - #ifdef TEST - *logofs << "handleRead: Render extension opcode for FD#" << fd_ - << " is " << (unsigned int) opcodeStore_ -> renderExtension - << ".\n" << logofs_flush; - #endif - } - - priority_++; - } - else - { - #ifdef TEST - *logofs << "handleRead: Received tainted X_QueryExtension reply " - << "for request OPCODE#" << requestData[0] << " with " - << "sequence " << sequenceNum << ".\n" - << logofs_flush; - #endif - - if (requestData[0] == opcodeStore_ -> getShmemParameters) - { - if (handleShmemReply(encodeBuffer, requestOpcode, requestData[1], - inputMessage, inputLength) < 0) - { - return -1; - } - - priority_++; - } - // - // Account this data to the original opcode. - // - - requestOpcode = requestData[0]; - } - } - break; - case X_QueryFont: - { - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_QueryFont); - - if (handleEncodeCached(encodeBuffer, serverCache_, messageStore, - inputMessage, inputLength)) - { - priority_++; - - hit = 1; - - break; - } - - // Differential encoding. - encodeBuffer.encodeBoolValue(1); - - unsigned int numProperties = GetUINT(inputMessage + 46, bigEndian_); - unsigned int numCharInfos = GetULONG(inputMessage + 56, bigEndian_); - encodeBuffer.encodeValue(numProperties, 16, 8); - encodeBuffer.encodeValue(numCharInfos, 32, 10); - handleEncodeCharInfo(inputMessage + 8, encodeBuffer); - handleEncodeCharInfo(inputMessage + 24, encodeBuffer); - encodeBuffer.encodeValue(GetUINT(inputMessage + 40, bigEndian_), 16, 9); - encodeBuffer.encodeValue(GetUINT(inputMessage + 42, bigEndian_), 16, 9); - encodeBuffer.encodeValue(GetUINT(inputMessage + 44, bigEndian_), 16, 9); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[48]); - encodeBuffer.encodeValue((unsigned int) inputMessage[49], 8); - encodeBuffer.encodeValue((unsigned int) inputMessage[50], 8); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[51]); - encodeBuffer.encodeValue(GetUINT(inputMessage + 52, bigEndian_), 16, 9); - encodeBuffer.encodeValue(GetUINT(inputMessage + 54, bigEndian_), 16, 9); - const unsigned char *nextSrc = inputMessage + 60; - unsigned int index; - - int end = 0; - - if (ServerCache::queryFontFontCache.lookup(numProperties * 8 + - numCharInfos * 12, nextSrc, index)) - { - encodeBuffer.encodeBoolValue(1); - encodeBuffer.encodeValue(index, 4); - - end = 1; - } - - if (end == 0) - { - encodeBuffer.encodeBoolValue(0); - for (; numProperties; numProperties--) - { - encodeBuffer.encodeValue(GetULONG(nextSrc, bigEndian_), 32, 9); - encodeBuffer.encodeValue(GetULONG(nextSrc + 4, bigEndian_), 32, 9); - nextSrc += 8; - } - for (; numCharInfos; numCharInfos--) - { - handleEncodeCharInfo(nextSrc, encodeBuffer); - - nextSrc += 12; - } - } - - priority_++; - } - break; - case X_QueryPointer: - { - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> queryPointerRootCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), - 29, serverCache_ -> queryPointerChildCache, 9); - unsigned int rootX = GetUINT(inputMessage + 16, bigEndian_); - unsigned int rootY = GetUINT(inputMessage + 18, bigEndian_); - unsigned int eventX = GetUINT(inputMessage + 20, bigEndian_); - unsigned int eventY = GetUINT(inputMessage + 22, bigEndian_); - eventX -= rootX; - eventY -= rootY; - encodeBuffer.encodeCachedValue( - rootX - serverCache_ -> motionNotifyLastRootX, 16, - serverCache_ -> motionNotifyRootXCache, 8); - serverCache_ -> motionNotifyLastRootX = rootX; - encodeBuffer.encodeCachedValue( - rootY - serverCache_ -> motionNotifyLastRootY, 16, - serverCache_ -> motionNotifyRootYCache, 8); - serverCache_ -> motionNotifyLastRootY = rootY; - encodeBuffer.encodeCachedValue(eventX, 16, - serverCache_ -> motionNotifyEventXCache, 8); - encodeBuffer.encodeCachedValue(eventY, 16, - serverCache_ -> motionNotifyEventYCache, 8); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 24, bigEndian_), - 16, serverCache_ -> motionNotifyStateCache); - priority_++; - } - break; - case X_QueryTree: - { - // - // This was very inefficient. In practice - // it just copied data on the output. Now - // it obtains an average 7:1 compression - // and could optionally be cached. - // - - unsigned int children = GetUINT(inputMessage + 16, bigEndian_); - - encodeBuffer.encodeValue(children, 16, 8); - - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, - serverCache_ -> queryTreeWindowCache); - - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), 29, - serverCache_ -> queryTreeWindowCache); - - const unsigned char *next = inputMessage + 32; - - for (unsigned int i = 0; i < children; i++) - { - encodeBuffer.encodeCachedValue(GetULONG(next + (i * 4), bigEndian_), 29, - serverCache_ -> queryTreeWindowCache); - } - - priority_++; - } - break; - case X_TranslateCoords: - { - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> translateCoordsChildCache, 9); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 12, bigEndian_), - 16, serverCache_ -> translateCoordsXCache, 8); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 14, bigEndian_), - 16, serverCache_ -> translateCoordsYCache, 8); - priority_++; - } - break; - case X_GetImage: - { - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_GetImage); - - if (handleEncodeCached(encodeBuffer, serverCache_, messageStore, - inputMessage, inputLength)) - { - priority_++; - - hit = 1; - - break; - } - - // Depth. - encodeBuffer.encodeCachedValue(inputMessage[1], 8, - serverCache_ -> depthCache); - // Reply length. - encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 9); - - // Visual. - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, - serverCache_ -> visualCache); - - // Since ProtoStep8 (#issue 108) - handleCopy(encodeBuffer, requestOpcode, messageStore -> - dataOffset, inputMessage, inputLength); - - priority_++; - } - break; - case X_GetPointerMapping: - { - encodeBuffer.encodeValue(inputMessage[1], 8, 4); - encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 4); - for (unsigned int i = 32; i < inputLength; i++) - encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8, 4); - - priority_++; - } - break; - case X_GetKeyboardControl: - { - encodeBuffer.encodeValue(inputMessage[1], 8, 2); - encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 8); - for (unsigned int i = 8; i < inputLength; i++) - encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8, 4); - - priority_++; - } - break; - default: - { - #ifdef PANIC - *logofs << "ServerChannel: PANIC! No matching request with " - << "OPCODE#" << (unsigned int) requestOpcode - << " for reply with sequence number " - << requestSequenceNum << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": No matching request with OPCODE#" - << (unsigned int) requestOpcode << " for reply with " - << "sequence number " << requestSequenceNum << ".\n"; - - return -1; - } - } - - bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) - - const char *cacheString = (hit ? "cached " : ""); - - *logofs << "handleRead: Handled " << cacheString << "reply to OPCODE#" - << (unsigned int) requestOpcode << " (" << DumpOpcode(requestOpcode) - << ") for FD#" << fd_ << " sequence " << serverSequence_ - << ". " << inputLength << " bytes in, " << bits << " bits (" - << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; - - #endif - - } // End of if (sequenceQueue_.peek(requestSequenceNum, requestOpcode) && ... - else - { - // - // We didn't push the request opcode. - // Check if fast encoding is required. - // - - requestOpcode = X_Reply; - - if (control -> LocalDeltaCompression == 0) - { - int result = handleFastReadReply(encodeBuffer, requestOpcode, - inputMessage, inputLength); - if (result < 0) - { - return -1; - } - else if (result > 0) - { - continue; - } - } - - // - // Group all replies whose opcode was not - // pushed in sequence number queue under - // the category 'generic reply'. - // - - #ifdef DEBUG - *logofs << "handleRead: Identified generic reply.\n" - << logofs_flush; - #endif - - MessageStore *messageStore = serverStore_ -> - getReplyStore(X_NXInternalGenericReply); - - hit = handleEncode(encodeBuffer, serverCache_, messageStore, - requestOpcode, inputMessage, inputLength); - - priority_++; - - bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) - - const char *cacheString = (hit ? "cached " : ""); - - *logofs << "handleRead: Handled " << cacheString << "generic reply " - << "OPCODE#" << X_NXInternalGenericReply << " for FD#" << fd_ - << " sequence " << serverSequence_ << ". " << inputLength - << " bytes in, " << bits << " bits (" << ((float) bits) / 8 - << " bytes) out.\n" << logofs_flush; - - #endif - } - - if (hit) - { - statistics -> addCachedReply(requestOpcode); - } - - statistics -> addReplyBits(requestOpcode, inputLength << 3, bits); - - } // End of if (inputMessage[0] == 1) ... - else - { - // - // Event or error. - // - - unsigned char inputOpcode = *inputMessage; - - unsigned int inputSequence = GetUINT(inputMessage + 2, bigEndian_); - - // - // Check if this is an event which we can discard. - // - - if ((inputOpcode == Expose && enableExpose_ == 0) || - (inputOpcode == GraphicsExpose && enableGraphicsExpose_ == 0) || - (inputOpcode == NoExpose && enableNoExpose_ == 0)) - { - continue; - } - else if (shmemState_ != NULL && shmemState_ -> enabled == 1 && - inputOpcode == shmemState_ -> event && - checkShmemEvent(inputOpcode, inputSequence, - inputMessage) > 0) - { - continue; - } - else if (inputOpcode == MotionNotify) - { - // - // Save the motion event and send when another - // event or error is received or the motion ti- - // meout is elapsed. If a previous motion event - // was already saved, we replace it with the - // new one and don't reset the timeout, so we - // still have a motion event every given ms. - // - - memcpy(lastMotion_, inputMessage, 32); - - #ifdef TEST - *logofs << "handleRead: Saved suppressed motion event for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - continue; - } - else if (inputOpcode == X_Error) - { - // - // Check if this is an error that matches a - // sequence number for which we are expecting - // a reply. - // - - unsigned short int errorSequenceNum; - unsigned char errorOpcode; - - if (sequenceQueue_.peek(errorSequenceNum, errorOpcode) && - ((unsigned int) errorSequenceNum == inputSequence)) - { - sequenceQueue_.pop(errorSequenceNum, errorOpcode); - } - - // - // Check if error is due to an image commit - // generated at the end of a split. - // - - if (checkCommitError(*(inputMessage + 1), inputSequence, inputMessage) > 0) - { - #ifdef TEST - *logofs << "handleRead: Skipping error on image commit for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - continue; - } - - // - // Check if it's an error generated by a request - // concerning shared memory support. - // - - else if (shmemState_ != NULL && (shmemState_ -> sequence == - inputSequence || (shmemState_ -> enabled == 1 && - (shmemState_ -> opcode == *(inputMessage + 10) || - shmemState_ -> error == *(inputMessage + 1)))) && - checkShmemError(*(inputMessage + 1), inputSequence, - inputMessage) > 0) - { - #ifdef TEST - *logofs << "handleRead: Skipping error on shmem operation for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - continue; - } - } - // - // Check if user pressed the CTRL+ALT+SHIFT+ESC key - // sequence because was unable to kill the session - // through the normal procedure. - // - - if (inputOpcode == KeyPress) - { - if (checkKeyboardEvent(inputOpcode, inputSequence, inputMessage) == 1) - { - #ifdef TEST - *logofs << "handleRead: Removing the key sequence from the " - << "event stream for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - continue; - } - } - - // - // We are going to handle an event or error - // that's not a mouse motion. Prepend any - // saved motion to it. - // - - if (lastMotion_[0] != '\0') - { - if (handleMotion(encodeBuffer) < 0) - { - #ifdef PANIC - *logofs << "handleRead: PANIC! Can't encode motion event for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't encode motion event for FD#" - << fd_ << ".\n"; - - return -1; - } - } - - // - // Encode opcode and difference between - // current sequence and the last one. - // - - encodeBuffer.encodeOpcodeValue(inputOpcode, serverCache_ -> opcodeCache); - - unsigned int sequenceDiff = inputSequence - serverSequence_; - - serverSequence_ = inputSequence; - - #ifdef DEBUG - *logofs << "handleRead: Last server sequence number for FD#" - << fd_ << " is " << serverSequence_ << " with " - << "difference " << sequenceDiff << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(sequenceDiff, 16, - serverCache_ -> eventSequenceCache, 7); - - // - // If differential compression is disabled - // then use the most simple encoding. - // - - if (control -> LocalDeltaCompression == 0) - { - int result = handleFastReadEvent(encodeBuffer, inputOpcode, - inputMessage, inputLength); - if (result < 0) - { - return -1; - } - else if (result > 0) - { - continue; - } - } - - switch (inputOpcode) - { - case X_Error: - { - // - // Set the priority flag in the case of - // a X protocol error. This may restart - // the client if it was waiting for the - // reply. - // - - priority_++; - - unsigned char errorCode = *(inputMessage + 1); - - encodeBuffer.encodeCachedValue(errorCode, 8, - serverCache_ -> errorCodeCache); - - if (errorCode != 11 && errorCode != 8 && - errorCode != 15 && errorCode != 1) - { - encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 16); - } - - if (errorCode >= 18) - { - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, - serverCache_ -> errorMinorCache); - } - - encodeBuffer.encodeCachedValue(inputMessage[10], 8, - serverCache_ -> errorMajorCache); - - if (errorCode >= 18) - { - const unsigned char *nextSrc = inputMessage + 11; - for (unsigned int i = 11; i < 32; i++) - encodeBuffer.encodeValue(*nextSrc++, 8); - } - } - break; - case ButtonPress: - case ButtonRelease: - case KeyPress: - case KeyRelease: - case MotionNotify: - case EnterNotify: - case LeaveNotify: - { - // - // Set the priority in the case this is - // an event that the remote side may - // care to receive as soon as possible. - // - - switch (inputOpcode) - { - case ButtonPress: - case ButtonRelease: - case KeyPress: - case KeyRelease: - { - priority_++; - } - } - - unsigned char detail = inputMessage[1]; - if (*inputMessage == MotionNotify) - encodeBuffer.encodeBoolValue((unsigned int) detail); - else if ((*inputMessage == EnterNotify) || (*inputMessage == LeaveNotify)) - encodeBuffer.encodeValue((unsigned int) detail, 3); - else if (*inputMessage == KeyRelease) - { - if (detail == serverCache_ -> keyPressLastKey) - encodeBuffer.encodeBoolValue(1); - else - { - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeValue((unsigned int) detail, 8); - } - } - else if ((*inputMessage == ButtonPress) || (*inputMessage == ButtonRelease)) - encodeBuffer.encodeCachedValue(detail, 8, - serverCache_ -> buttonCache); - else - encodeBuffer.encodeValue((unsigned int) detail, 8); - unsigned int timestamp = GetULONG(inputMessage + 4, bigEndian_); - unsigned int timestampDiff = - timestamp - serverCache_ -> lastTimestamp; - serverCache_ -> lastTimestamp = timestamp; - encodeBuffer.encodeCachedValue(timestampDiff, 32, - serverCache_ -> motionNotifyTimestampCache, 9); - int skipRest = 0; - if (*inputMessage == KeyRelease) - { - skipRest = 1; - for (unsigned int i = 8; i < 31; i++) - { - if (inputMessage[i] != serverCache_ -> keyPressCache[i - 8]) - { - skipRest = 0; - break; - } - } - encodeBuffer.encodeBoolValue(skipRest); - } - - if (!skipRest) - { - const unsigned char *nextSrc = inputMessage + 8; - for (unsigned int i = 0; i < 3; i++) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29, - *serverCache_ -> motionNotifyWindowCache[i], 6); - nextSrc += 4; - } - unsigned int rootX = GetUINT(inputMessage + 20, bigEndian_); - unsigned int rootY = GetUINT(inputMessage + 22, bigEndian_); - unsigned int eventX = GetUINT(inputMessage + 24, bigEndian_); - unsigned int eventY = GetUINT(inputMessage + 26, bigEndian_); - eventX -= rootX; - eventY -= rootY; - encodeBuffer.encodeCachedValue(rootX - - serverCache_ -> motionNotifyLastRootX, 16, - serverCache_ -> motionNotifyRootXCache, 6); - serverCache_ -> motionNotifyLastRootX = rootX; - encodeBuffer.encodeCachedValue(rootY - - serverCache_ -> motionNotifyLastRootY, 16, - serverCache_ -> motionNotifyRootYCache, 6); - serverCache_ -> motionNotifyLastRootY = rootY; - encodeBuffer.encodeCachedValue(eventX, 16, - serverCache_ -> motionNotifyEventXCache, 6); - encodeBuffer.encodeCachedValue(eventY, 16, - serverCache_ -> motionNotifyEventYCache, 6); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 28, bigEndian_), - 16, serverCache_ -> motionNotifyStateCache); - if ((*inputMessage == EnterNotify) || (*inputMessage == LeaveNotify)) - encodeBuffer.encodeValue((unsigned int) inputMessage[30], 2); - else - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[30]); - if ((*inputMessage == EnterNotify) || (*inputMessage == LeaveNotify)) - encodeBuffer.encodeValue((unsigned int) inputMessage[31], 2); - else if (*inputMessage == KeyPress) - { - serverCache_ -> keyPressLastKey = detail; - for (unsigned int i = 8; i < 31; i++) - { - serverCache_ -> keyPressCache[i - 8] = inputMessage[i]; - } - } - } - } - break; - case ColormapNotify: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), - 29, serverCache_ -> colormapNotifyWindowCache, 8); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> colormapNotifyColormapCache, 8); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[12]); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[13]); - } - break; - case ConfigureNotify: - { - const unsigned char *nextSrc = inputMessage + 4; - for (unsigned int i = 0; i < 3; i++) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29, - *serverCache_ -> configureNotifyWindowCache[i], 9); - nextSrc += 4; - } - for (unsigned int j = 0; j < 5; j++) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *serverCache_ -> configureNotifyGeomCache[j], 8); - nextSrc += 2; - } - encodeBuffer.encodeBoolValue(*nextSrc); - } - break; - case CreateNotify: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), - 29, serverCache_ -> createNotifyWindowCache, 9); - unsigned int window = GetULONG(inputMessage + 8, bigEndian_); - encodeBuffer.encodeValue(window - - serverCache_ -> createNotifyLastWindow, 29, 5); - serverCache_ -> createNotifyLastWindow = window; - const unsigned char* nextSrc = inputMessage + 12; - for (unsigned int i = 0; i < 5; i++) - { - encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16, 9); - nextSrc += 2; - } - encodeBuffer.encodeBoolValue(*nextSrc); - } - break; - case Expose: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, - serverCache_ -> exposeWindowCache, 9); - const unsigned char *nextSrc = inputMessage + 8; - for (unsigned int i = 0; i < 5; i++) - { - encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, - *serverCache_ -> exposeGeomCache[i], 6); - nextSrc += 2; - } - } - break; - case FocusIn: - case FocusOut: - { - encodeBuffer.encodeValue((unsigned int) inputMessage[1], 3); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), - 29, serverCache_ -> focusInWindowCache, 9); - encodeBuffer.encodeValue((unsigned int) inputMessage[8], 2); - } - break; - case KeymapNotify: - { - if (ServerCache::lastKeymap.compare(31, inputMessage + 1)) - encodeBuffer.encodeBoolValue(1); - else - { - encodeBuffer.encodeBoolValue(0); - const unsigned char *nextSrc = inputMessage + 1; - for (unsigned int i = 1; i < 32; i++) - encodeBuffer.encodeValue((unsigned int) *nextSrc++, 8); - } - } - break; - case MapNotify: - case UnmapNotify: - case DestroyNotify: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), - 29, serverCache_ -> mapNotifyEventCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> mapNotifyWindowCache, 9); - if ((*inputMessage == MapNotify) || (*inputMessage == UnmapNotify)) - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[12]); - } - break; - case NoExpose: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), - 29, serverCache_ -> noExposeDrawableCache, 9); - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, - serverCache_ -> noExposeMinorCache); - encodeBuffer.encodeCachedValue(inputMessage[10], 8, - serverCache_ -> noExposeMajorCache); - } - break; - case PropertyNotify: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), - 29, serverCache_ -> propertyNotifyWindowCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> propertyNotifyAtomCache, 9); - unsigned int timestamp = GetULONG(inputMessage + 12, bigEndian_); - unsigned int timestampDiff = - timestamp - serverCache_ -> lastTimestamp; - serverCache_ -> lastTimestamp = timestamp; - encodeBuffer.encodeValue(timestampDiff, 32, 9); - encodeBuffer.encodeBoolValue((unsigned int) inputMessage[16]); - } - break; - case ReparentNotify: - { - const unsigned char* nextSrc = inputMessage + 4; - for (unsigned int i = 0; i < 3; i++) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), - 29, serverCache_ -> reparentNotifyWindowCache, 9); - nextSrc += 4; - } - encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16, 6); - encodeBuffer.encodeValue(GetUINT(nextSrc + 2, bigEndian_), 16, 6); - encodeBuffer.encodeBoolValue((unsigned int)inputMessage[20]); - } - break; - case SelectionClear: - { - unsigned int timestamp = GetULONG(inputMessage + 4, bigEndian_); - unsigned int timestampDiff = timestamp - serverCache_ -> lastTimestamp; - serverCache_ -> lastTimestamp = timestamp; - encodeBuffer.encodeValue(timestampDiff, 32, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> selectionClearWindowCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), - 29, serverCache_ -> selectionClearAtomCache, 9); - } - break; - case SelectionRequest: - { - unsigned int timestamp = GetULONG(inputMessage + 4, bigEndian_); - unsigned int timestampDiff = timestamp - serverCache_ -> lastTimestamp; - serverCache_ -> lastTimestamp = timestamp; - encodeBuffer.encodeValue(timestampDiff, 32, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), - 29, serverCache_ -> selectionClearWindowCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), - 29, serverCache_ -> selectionClearWindowCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), - 29, serverCache_ -> selectionClearAtomCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 20, bigEndian_), - 29, serverCache_ -> selectionClearAtomCache, 9); - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 24, bigEndian_), - 29, serverCache_ -> selectionClearAtomCache, 9); - } - break; - case VisibilityNotify: - { - encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), - 29, serverCache_ -> visibilityNotifyWindowCache, 9); - encodeBuffer.encodeValue((unsigned int) inputMessage[8], 2); - } - break; - default: - { - #ifdef TEST - *logofs << "handleRead: Using generic event compression " - << "for OPCODE#" << (unsigned int) inputOpcode - << ".\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(*(inputMessage + 1), 8, - serverCache_ -> genericEventCharCache); - - for (unsigned int i = 0; i < 14; i++) - { - encodeBuffer.encodeCachedValue(GetUINT(inputMessage + i * 2 + 4, bigEndian_), - 16, *serverCache_ -> genericEventIntCache[i]); - } - } - - } // switch (inputOpcode)... - - int bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) - - if (*inputMessage == X_Error) - { - unsigned char code = *(inputMessage + 1); - - *logofs << "handleRead: Handled error ERR_CODE#" - << (unsigned int) code << " for FD#" << fd_; - - *logofs << " RES_ID#" << GetULONG(inputMessage + 4, bigEndian_); - - *logofs << " MIN_OP#" << GetUINT(inputMessage + 8, bigEndian_); - - *logofs << " MAJ_OP#" << (unsigned int) *(inputMessage + 10); - - *logofs << " sequence " << inputSequence << ". " << inputLength - << " bytes in, " << bits << " bits (" << ((float) bits) / 8 - << " bytes) out.\n" << logofs_flush; - } - else - { - *logofs << "handleRead: Handled event OPCODE#" - << (unsigned int) *inputMessage << " for FD#" << fd_ - << " sequence " << inputSequence << ". " << inputLength - << " bytes in, " << bits << " bits (" << ((float) bits) / 8 - << " bytes) out.\n" << logofs_flush; - } - - #endif - - statistics -> addEventBits(*inputMessage, inputLength << 3, bits); - - } // End of if (inputMessage[0] == X_Reply) ... else ... - - } // End of if (firstReply_) ... else ... - - } // End of while ((inputMessage = readBuffer_.getMessage(inputLength)) != 0) ... - - // - // Check if we need to flush because of - // prioritized data. - // - - if (priority_ > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleRead: WARNING! Requesting flush " - << "because of " << priority_ << " prioritized " - << "messages for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - if (proxy -> handleAsyncPriority() < 0) - { - return -1; - } - - // - // Reset the priority flag. - // - - priority_ = 0; - } - - // - // Flush if we produced enough data. - // - - if (proxy -> canAsyncFlush() == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleRead: WARNING! Requesting flush " - << "because of token length exceeded.\n" - << logofs_flush; - #endif - - if (proxy -> handleAsyncFlush() < 0) - { - return -1; - } - } - - #if defined(TEST) || defined(INFO) - - if (transport_ -> pending() != 0 || - readBuffer_.checkMessage() != 0) - { - *logofs << "handleRead: PANIC! Buffer for X descriptor FD#" - << fd_ << " has " << transport_ -> pending() - << " bytes to read.\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - // - // Reset the read buffer. - // - - readBuffer_.fullReset(); - - return 1; -} - -// -// End of handleRead(). -// - -// -// Beginning of handleWrite(). -// - -int ServerChannel::handleWrite(const unsigned char *message, unsigned int length) -{ - #ifdef TEST - *logofs << "handleWrite: Called for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - // - // Create the buffer from which to - // decode messages. - // - - DecodeBuffer decodeBuffer(message, length); - - #if defined(TEST) || defined(INFO) || defined(FLUSH) - *logofs << "handleWrite: Decoding messages for FD#" << fd_ - << " with " << length << " bytes in the buffer.\n" - << logofs_flush; - #endif - - if (firstRequest_) - { - // - // Need to add the length of the first request - // because it was not present in the previous - // versions. Length of the first request was - // assumed to be the same as the encode buffer - // but this may be not the case if a different - // encoding is used. - // - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeValue(length, 8); - - unsigned int nextByte; - unsigned char *outputMessage = writeBuffer_.addMessage(length); - unsigned char *nextDest = outputMessage; - - for (unsigned int i = 0; i < length; i++) - { - decodeBuffer.decodeValue(nextByte, 8); - - *nextDest++ = (unsigned char) nextByte; - } - - if (*outputMessage == 0x42) - { - setBigEndian(1); - } - else - { - setBigEndian(0); - } - - #ifdef TEST - *logofs << "handleWrite: First request detected.\n" << logofs_flush; - #endif - - // - // Handle the fake authorization cookie. - // - - if (handleAuthorization(outputMessage) < 0) - { - return -1; - } - - firstRequest_ = 0; - - } // End of if (firstRequest_) - - // - // This was previously in a 'else' block. - // Due to the way the first request was - // handled, we could not decode multiple - // messages in the first frame. - // - - { // Start of the decoding block. - - unsigned char outputOpcode; - - unsigned char *outputMessage; - unsigned int outputLength; - - // - // Set when message is found in cache. - // - - int hit; - - while (decodeBuffer.decodeOpcodeValue(outputOpcode, clientCache_ -> opcodeCache, 1)) - { - hit = 0; - - // - // Splits are sent by client proxy outside the - // normal read loop. As we 'insert' splits in - // the real client-server X protocol, we must - // avoid to increment the sequence number or - // our clients would get confused. - // - - if (outputOpcode != opcodeStore_ -> splitData) - { - clientSequence_++; - clientSequence_ &= 0xffff; - - #ifdef DEBUG - *logofs << "handleWrite: Last client sequence number for FD#" - << fd_ << " is " << clientSequence_ << ".\n" - << logofs_flush; - #endif - } - else - { - // - // It's a split, not a normal - // burst of proxy data. - // - - handleSplit(decodeBuffer); - - continue; - } - - #ifdef SUSPEND - - if (clientSequence_ == 1000) - { - cerr << "Warning" << ": Exiting to test the resilience of the agent.\n"; - - sleep(2); - - HandleAbort(); - } - - #endif - - // - // Is differential encoding disabled? - // - - if (control -> RemoteDeltaCompression == 0) - { - int result = handleFastWriteRequest(decodeBuffer, outputOpcode, - outputMessage, outputLength); - if (result < 0) - { - return -1; - } - else if (result > 0) - { - continue; - } - } - - // - // General-purpose temp variables for - // decoding ints and chars. - // - - unsigned int value; - unsigned char cValue; - - #ifdef DEBUG - *logofs << "handleWrite: Going to handle request OPCODE#" - << (unsigned int) outputOpcode << " (" << DumpOpcode(outputOpcode) - << ") for FD#" << fd_ << " sequence " << clientSequence_ - << ".\n" << logofs_flush; - #endif - - switch (outputOpcode) - { - case X_AllocColor: - { - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> colormapCache); - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned char *nextDest = outputMessage + 8; - unsigned int colorData[3]; - - for (unsigned int i = 0; i < 3; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *(clientCache_ -> allocColorRGBCache[i]), 4); - PutUINT(value, nextDest, bigEndian_); - colorData[i] = value; - nextDest += 2; - } - - sequenceQueue_.push(clientSequence_, outputOpcode, - colorData[0], colorData[1], colorData[2]); - } - break; - case X_ReparentWindow: - { - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeValue(value, 16, 11); - PutUINT(value, outputMessage + 12, bigEndian_); - decodeBuffer.decodeValue(value, 16, 11); - PutUINT(value, outputMessage + 14, bigEndian_); - } - break; - case X_ChangeProperty: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ChangeProperty); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - unsigned char format; - decodeBuffer.decodeCachedValue(format, 8, - clientCache_ -> changePropertyFormatCache); - unsigned int dataLength; - decodeBuffer.decodeValue(dataLength, 32, 6); - outputLength = 24 + RoundUp4(dataLength * (format >> 3)); - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 2); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> changePropertyPropertyCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> changePropertyTypeCache, 9); - PutULONG(value, outputMessage + 12, bigEndian_); - outputMessage[16] = format; - PutULONG(dataLength, outputMessage + 20, bigEndian_); - unsigned char *nextDest = outputMessage + 24; - - if (format == 8) - { - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, dataLength); - } - else if (format == 32) - { - for (unsigned int i = 0; i < dataLength; i++) - { - decodeBuffer.decodeCachedValue(value, 32, - clientCache_ -> changePropertyData32Cache); - - PutULONG(value, nextDest, bigEndian_); - - nextDest += 4; - } - } - else - { - for (unsigned int i = 0; i < dataLength; i++) - { - decodeBuffer.decodeValue(value, 16); - - PutUINT(value, nextDest, bigEndian_); - - nextDest += 2; - } - } - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_SendEvent: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_SendEvent); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 44; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeBoolValue(value); - *(outputMessage + 1) = value; - decodeBuffer.decodeBoolValue(value); - if (value) - { - decodeBuffer.decodeBoolValue(value); - } - else - { - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - } - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 32, - clientCache_ -> sendEventMaskCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(*(outputMessage + 12), 8, - clientCache_ -> sendEventCodeCache); - decodeBuffer.decodeCachedValue(*(outputMessage + 13), 8, - clientCache_ -> sendEventByteDataCache); - decodeBuffer.decodeValue(value, 16, 4); - clientCache_ -> sendEventLastSequence += value; - clientCache_ -> sendEventLastSequence &= 0xffff; - PutUINT(clientCache_ -> sendEventLastSequence, outputMessage + 14, bigEndian_); - decodeBuffer.decodeCachedValue(value, 32, - clientCache_ -> sendEventIntDataCache); - PutULONG(value, outputMessage + 16, bigEndian_); - - for (unsigned int i = 20; i < 44; i++) - { - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache_ -> sendEventEventCache); - *(outputMessage + i) = cValue; - } - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_ChangeWindowAttributes: - { - unsigned int numAttrs; - decodeBuffer.decodeValue(numAttrs, 4); - outputLength = 12 + (numAttrs << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned int bitmask; - decodeBuffer.decodeCachedValue(bitmask, 15, - clientCache_ -> createWindowBitmaskCache); - PutULONG(bitmask, outputMessage + 8, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - unsigned int mask = 0x1; - for (unsigned int i = 0; i < 15; i++) - { - if (bitmask & mask) - { - decodeBuffer.decodeCachedValue(value, 32, - *clientCache_ -> createWindowAttrCache[i]); - PutULONG(value, nextDest, bigEndian_); - nextDest += 4; - } - mask <<= 1; - } - } - break; - case X_ClearArea: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ClearArea); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeBoolValue(value); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned char *nextDest = outputMessage + 8; - for (unsigned int i = 0; i < 4; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> clearAreaGeomCache[i], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_CloseFont: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 29, 5); - clientCache_ -> lastFont += value; - clientCache_ -> lastFont &= 0x1fffffff; - PutULONG(clientCache_ -> lastFont, outputMessage + 4, bigEndian_); - } - break; - case X_ConfigureWindow: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ConfigureWindow); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 12; - outputMessage = writeBuffer_.addMessage(outputLength); - writeBuffer_.registerPointer(&outputMessage); - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned int bitmask; - decodeBuffer.decodeCachedValue(bitmask, 7, - clientCache_ -> configureWindowBitmaskCache); - PutUINT(bitmask, outputMessage + 8, bigEndian_); - unsigned int mask = 0x1; - for (unsigned int i = 0; i < 7; i++) - { - if (bitmask & mask) - { - unsigned char* nextDest = writeBuffer_.addMessage(4); - outputLength += 4; - decodeBuffer.decodeCachedValue(value, CONFIGUREWINDOW_FIELD_WIDTH[i], - *clientCache_ -> configureWindowAttrCache[i], 8); - PutULONG(value, nextDest, bigEndian_); - nextDest += 4; - } - mask <<= 1; - } - writeBuffer_.unregisterPointer(); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_ConvertSelection: - { - outputLength = 24; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> convertSelectionRequestorCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned char* nextDest = outputMessage + 8; - for (unsigned int i = 0; i < 3; i++) - { - decodeBuffer.decodeCachedValue(value, 29, - *(clientCache_ -> convertSelectionAtomCache[i]), 9); - PutULONG(value, nextDest, bigEndian_); - nextDest += 4; - } - decodeBuffer.decodeValue(value, 32, 4); - clientCache_ -> convertSelectionLastTimestamp += value; - PutULONG(clientCache_ -> convertSelectionLastTimestamp, - nextDest, bigEndian_); - } - break; - case X_CopyArea: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_CopyArea); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 28; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 12, bigEndian_); - unsigned char *nextDest = outputMessage + 16; - for (unsigned int i = 0; i < 6; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> copyAreaGeomCache[i], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_CopyGC: - { - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 23, - clientCache_ -> createGCBitmaskCache); - PutULONG(value, outputMessage + 12, bigEndian_); - } - break; - case X_CopyPlane: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 12, bigEndian_); - unsigned char *nextDest = outputMessage + 16; - for (unsigned int i = 0; i < 6; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> copyPlaneGeomCache[i], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - decodeBuffer.decodeCachedValue(value, 32, - clientCache_ -> copyPlaneBitPlaneCache, 10); - PutULONG(value, outputMessage + 28, bigEndian_); - } - break; - case X_CreateGC: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_CreateGC); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - writeBuffer_.registerPointer(&outputMessage); - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeNewXidValue(value, clientCache_ -> lastId, - clientCache_ -> lastIdCache, clientCache_ -> gcCache, - clientCache_ -> freeGCCache); - - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned int offset = 8; - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + offset, bigEndian_); - offset += 4; - unsigned int bitmask; - decodeBuffer.decodeCachedValue(bitmask, 23, - clientCache_ -> createGCBitmaskCache); - PutULONG(bitmask, outputMessage + offset, bigEndian_); - unsigned int mask = 0x1; - for (unsigned int i = 0; i < 23; i++) - { - if (bitmask & mask) - { - unsigned char* nextDest = writeBuffer_.addMessage(4); - outputLength += 4; - unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i]; - if (fieldWidth <= 4) - decodeBuffer.decodeValue(value, fieldWidth); - else - decodeBuffer.decodeCachedValue(value, fieldWidth, - *clientCache_ -> createGCAttrCache[i]); - PutULONG(value, nextDest, bigEndian_); - } - mask <<= 1; - } - writeBuffer_.unregisterPointer(); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_ChangeGC: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ChangeGC); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 12; - outputMessage = writeBuffer_.addMessage(outputLength); - writeBuffer_.registerPointer(&outputMessage); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned int offset = 8; - unsigned int bitmask; - decodeBuffer.decodeCachedValue(bitmask, 23, - clientCache_ -> createGCBitmaskCache); - PutULONG(bitmask, outputMessage + offset, bigEndian_); - unsigned int mask = 0x1; - for (unsigned int i = 0; i < 23; i++) - { - if (bitmask & mask) - { - unsigned char* nextDest = writeBuffer_.addMessage(4); - outputLength += 4; - unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i]; - if (fieldWidth <= 4) - decodeBuffer.decodeValue(value, fieldWidth); - else - decodeBuffer.decodeCachedValue(value, fieldWidth, - *clientCache_ -> createGCAttrCache[i]); - PutULONG(value, nextDest, bigEndian_); - } - mask <<= 1; - } - writeBuffer_.unregisterPointer(); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_CreatePixmap: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_CreatePixmap); - - hit = handleDecode(decodeBuffer, clientCache_, messageStore, - outputOpcode, outputMessage, outputLength); - } - break; - case X_CreateWindow: - { - outputLength = 32; - outputMessage = writeBuffer_.addMessage(outputLength); - writeBuffer_.registerPointer(&outputMessage); - decodeBuffer.decodeCachedValue(cValue, 8, clientCache_ -> depthCache); - outputMessage[1] = cValue; - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 8, bigEndian_); - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeNewXidValue(value, clientCache_ -> lastId, - clientCache_ -> lastIdCache, clientCache_ -> windowCache, - clientCache_ -> freeWindowCache); - - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - unsigned int i; - for (i = 0; i < 6; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> createWindowGeomCache[i], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - decodeBuffer.decodeCachedValue(value, 29, clientCache_ -> visualCache); - PutULONG(value, outputMessage + 24, bigEndian_); - unsigned int bitmask; - decodeBuffer.decodeCachedValue(bitmask, 15, - clientCache_ -> createWindowBitmaskCache); - PutULONG(bitmask, outputMessage + 28, bigEndian_); - unsigned int mask = 0x1; - for (i = 0; i < 15; i++) - { - if (bitmask & mask) - { - nextDest = writeBuffer_.addMessage(4); - outputLength += 4; - decodeBuffer.decodeCachedValue(value, 32, - *clientCache_ -> createWindowAttrCache[i]); - PutULONG(value, nextDest, bigEndian_); - } - mask <<= 1; - } - writeBuffer_.unregisterPointer(); - } - break; - case X_DeleteProperty: - { - outputLength = 12; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeValue(value, 29, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - } - break; - case X_FillPoly: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_FillPoly); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - unsigned int numPoints; - - // Since ProtoStep10 (#issue 108) - decodeBuffer.decodeCachedValue(numPoints, 16, - clientCache_ -> fillPolyNumPointsCache, 4); - - outputLength = 16 + (numPoints << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeValue(value, 2); - outputMessage[12] = (unsigned char) value; - unsigned int relativeCoordMode; - decodeBuffer.decodeBoolValue(relativeCoordMode); - outputMessage[13] = (unsigned char) relativeCoordMode; - unsigned char *nextDest = outputMessage + 16; - unsigned int pointIndex = 0; - for (unsigned int i = 0; i < numPoints; i++) - { - if (relativeCoordMode) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> fillPolyXRelCache[pointIndex], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> fillPolyYRelCache[pointIndex], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - else - { - unsigned int x, y; - decodeBuffer.decodeBoolValue(value); - if (value) - { - decodeBuffer.decodeValue(value, 3); - x = clientCache_ -> fillPolyRecentX[value]; - y = clientCache_ -> fillPolyRecentY[value]; - } - else - { - decodeBuffer.decodeCachedValue(x, 16, - *clientCache_ -> fillPolyXAbsCache[pointIndex], 8); - decodeBuffer.decodeCachedValue(y, 16, - *clientCache_ -> fillPolyYAbsCache[pointIndex], 8); - clientCache_ -> fillPolyRecentX[clientCache_ -> fillPolyIndex] = x; - clientCache_ -> fillPolyRecentY[clientCache_ -> fillPolyIndex] = y; - clientCache_ -> fillPolyIndex++; - if (clientCache_ -> fillPolyIndex == 8) - clientCache_ -> fillPolyIndex = 0; - } - PutUINT(x, nextDest, bigEndian_); - nextDest += 2; - PutUINT(y, nextDest, bigEndian_); - nextDest += 2; - } - - if (++pointIndex == 10) pointIndex = 0; - } - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_FreeColors: - { - unsigned int numPixels; - decodeBuffer.decodeValue(numPixels, 16, 4); - outputLength = 12 + (numPixels << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> colormapCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeValue(value, 32, 4); - PutULONG(value, outputMessage + 8, bigEndian_); - unsigned char* nextDest = outputMessage + 12; - while (numPixels) - { - decodeBuffer.decodeValue(value, 32, 8); - PutULONG(value, nextDest, bigEndian_); - nextDest += 4; - numPixels--; - } - } - break; - case X_FreeCursor: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, clientCache_ -> cursorCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - } - break; - case X_FreeGC: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeFreeXidValue(value, clientCache_ -> freeGCCache); - - PutULONG(value, outputMessage + 4, bigEndian_); - } - break; - case X_FreePixmap: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeFreeXidValue(value, clientCache_ -> freeDrawableCache); - - PutULONG(value, outputMessage + 4, bigEndian_); - } - break; - case X_GetAtomName: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 29, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_GetGeometry: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_GetInputFocus: - { - outputLength = 4; - outputMessage = writeBuffer_.addMessage(outputLength); - - sequenceQueue_.push(clientSequence_, outputOpcode, outputOpcode); - } - break; - case X_GetModifierMapping: - { - outputLength = 4; - outputMessage = writeBuffer_.addMessage(outputLength); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_GetKeyboardMapping: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 8); - outputMessage[4] = value; - decodeBuffer.decodeValue(value, 8); - outputMessage[5] = value; - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_GetProperty: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_GetProperty); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - // - // Save a reference to identify the reply. - // - - unsigned int property = GetULONG(outputMessage + 8, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode, property); - - break; - } - - outputLength = 24; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeBoolValue(value); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned int property; - decodeBuffer.decodeValue(property, 29, 9); - PutULONG(property, outputMessage + 8, bigEndian_); - decodeBuffer.decodeValue(value, 29, 9); - PutULONG(value, outputMessage + 12, bigEndian_); - decodeBuffer.decodeValue(value, 32, 2); - PutULONG(value, outputMessage + 16, bigEndian_); - decodeBuffer.decodeValue(value, 32, 8); - PutULONG(value, outputMessage + 20, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode, property); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_GetSelectionOwner: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> getSelectionOwnerSelectionCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_GrabButton: - case X_GrabPointer: - { - outputLength = 24; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeBoolValue(value); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> grabButtonEventMaskCache); - PutUINT(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeBoolValue(value); - outputMessage[10] = (unsigned char) value; - decodeBuffer.decodeBoolValue(value); - outputMessage[11] = (unsigned char) value; - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> grabButtonConfineCache, 9); - PutULONG(value, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> cursorCache, 9); - PutULONG(value, outputMessage + 16, bigEndian_); - if (outputOpcode == X_GrabButton) - { - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache_ -> grabButtonButtonCache); - outputMessage[20] = cValue; - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> grabButtonModifierCache); - PutUINT(value, outputMessage + 22, bigEndian_); - } - else - { - decodeBuffer.decodeValue(value, 32, 4); - clientCache_ -> grabKeyboardLastTimestamp += value; - PutULONG(clientCache_ -> grabKeyboardLastTimestamp, - outputMessage + 20, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - } - break; - case X_GrabKeyboard: - { - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeBoolValue(value); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeValue(value, 32, 4); - clientCache_ -> grabKeyboardLastTimestamp += value; - PutULONG(clientCache_ -> grabKeyboardLastTimestamp, outputMessage + 8, - bigEndian_); - decodeBuffer.decodeBoolValue(value); - outputMessage[12] = (unsigned char) value; - decodeBuffer.decodeBoolValue(value); - outputMessage[13] = (unsigned char) value; - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_GrabServer: - case X_UngrabServer: - case X_NoOperation: - { - #ifdef DEBUG - *logofs << "handleWrite: Managing (probably tainted) X_NoOperation request for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - outputLength = 4; - outputMessage = writeBuffer_.addMessage(outputLength); - } - break; - case X_PolyText8: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyText8); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> polyTextCacheX); - clientCache_ -> polyTextLastX += value; - clientCache_ -> polyTextLastX &= 0xffff; - PutUINT(clientCache_ -> polyTextLastX, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> polyTextCacheY); - clientCache_ -> polyTextLastY += value; - clientCache_ -> polyTextLastY &= 0xffff; - PutUINT(clientCache_ -> polyTextLastY, outputMessage + 14, bigEndian_); - unsigned int addedLength = 0; - writeBuffer_.registerPointer(&outputMessage); - for (;;) - { - decodeBuffer.decodeBoolValue(value); - if (!value) - break; - unsigned int textLength; - decodeBuffer.decodeValue(textLength, 8); - if (textLength == 255) - { - addedLength += 5; - unsigned char *nextSegment = writeBuffer_.addMessage(5); - *nextSegment = (unsigned char) textLength; - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> polyTextFontCache); - PutULONG(value, nextSegment + 1, 1); - } - else - { - addedLength += (textLength + 2); - unsigned char *nextSegment = - writeBuffer_.addMessage(textLength + 2); - *nextSegment = (unsigned char) textLength; - unsigned char *nextDest = nextSegment + 1; - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache_ -> polyTextDeltaCache); - *nextDest++ = cValue; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, textLength); - - nextDest += textLength; - } - } - outputLength += addedLength; - unsigned int mod4 = (addedLength & 0x3); - if (mod4) - { - unsigned int extra = 4 - mod4; - unsigned char *nextDest = writeBuffer_.addMessage(extra); - for (unsigned int i = 0; i < extra; i++) - *nextDest++ = 0; - outputLength += extra; - } - writeBuffer_.unregisterPointer(); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_PolyText16: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyText16); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> polyTextCacheX); - clientCache_ -> polyTextLastX += value; - clientCache_ -> polyTextLastX &= 0xffff; - PutUINT(clientCache_ -> polyTextLastX, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> polyTextCacheY); - clientCache_ -> polyTextLastY += value; - clientCache_ -> polyTextLastY &= 0xffff; - PutUINT(clientCache_ -> polyTextLastY, outputMessage + 14, bigEndian_); - unsigned int addedLength = 0; - writeBuffer_.registerPointer(&outputMessage); - for (;;) - { - decodeBuffer.decodeBoolValue(value); - if (!value) - break; - unsigned int textLength; - decodeBuffer.decodeValue(textLength, 8); - if (textLength == 255) - { - addedLength += 5; - unsigned char *nextSegment = writeBuffer_.addMessage(5); - *nextSegment = (unsigned char) textLength; - decodeBuffer.decodeCachedValue(value, 29, clientCache_ -> polyTextFontCache); - PutULONG(value, nextSegment + 1, 1); - } - else - { - addedLength += (textLength * 2 + 2); - unsigned char *nextSegment = - writeBuffer_.addMessage(textLength * 2 + 2); - *nextSegment = (unsigned char) textLength; - unsigned char *nextDest = nextSegment + 1; - decodeBuffer.decodeCachedValue(cValue, 8, clientCache_ -> polyTextDeltaCache); - *nextDest++ = cValue; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, textLength * 2); - - nextDest += textLength * 2; - } - } - outputLength += addedLength; - - unsigned int mod4 = (addedLength & 0x3); - if (mod4) - { - unsigned int extra = 4 - mod4; - unsigned char *nextDest = writeBuffer_.addMessage(extra); - for (unsigned int i = 0; i < extra; i++) - *nextDest++ = 0; - outputLength += extra; - } - writeBuffer_.unregisterPointer(); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_ImageText8: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ImageText8); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - unsigned int textLength; - decodeBuffer.decodeCachedValue(textLength, 8, - clientCache_ -> imageTextLengthCache, 4); - outputLength = 16 + RoundUp4(textLength); - outputMessage = writeBuffer_.addMessage(outputLength); - outputMessage[1] = (unsigned char) textLength; - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> imageTextCacheX); - clientCache_ -> imageTextLastX += value; - clientCache_ -> imageTextLastX &= 0xffff; - PutUINT(clientCache_ -> imageTextLastX, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> imageTextCacheY); - clientCache_ -> imageTextLastY += value; - clientCache_ -> imageTextLastY &= 0xffff; - PutUINT(clientCache_ -> imageTextLastY, outputMessage + 14, bigEndian_); - unsigned char *nextDest = outputMessage + 16; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, textLength); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_ImageText16: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_ImageText16); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - unsigned int textLength; - decodeBuffer.decodeCachedValue(textLength, 8, - clientCache_ -> imageTextLengthCache, 4); - outputLength = 16 + RoundUp4(textLength * 2); - outputMessage = writeBuffer_.addMessage(outputLength); - outputMessage[1] = (unsigned char) textLength; - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> imageTextCacheX); - clientCache_ -> imageTextLastX += value; - clientCache_ -> imageTextLastX &= 0xffff; - PutUINT(clientCache_ -> imageTextLastX, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> imageTextCacheY); - clientCache_ -> imageTextLastY += value; - clientCache_ -> imageTextLastY &= 0xffff; - PutUINT(clientCache_ -> imageTextLastY, outputMessage + 14, bigEndian_); - unsigned char *nextDest = outputMessage + 16; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, textLength * 2); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_InternAtom: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_InternAtom); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - sequenceQueue_.push(clientSequence_, outputOpcode); - - break; - } - - unsigned int nameLength; - decodeBuffer.decodeValue(nameLength, 16, 6); - outputLength = RoundUp4(nameLength) + 8; - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(nameLength, outputMessage + 4, bigEndian_); - decodeBuffer.decodeBoolValue(value); - outputMessage[1] = (unsigned char) value; - unsigned char *nextDest = outputMessage + 8; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, nameLength); - - sequenceQueue_.push(clientSequence_, outputOpcode); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_ListExtensions: - { - outputLength = 4; - outputMessage = writeBuffer_.addMessage(outputLength); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_ListFonts: - { - unsigned int textLength; - decodeBuffer.decodeValue(textLength, 16, 6); - outputLength = 8 + RoundUp4(textLength); - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(textLength, outputMessage + 6, bigEndian_); - decodeBuffer.decodeValue(value, 16, 6); - PutUINT(value, outputMessage + 4, bigEndian_); - unsigned char* nextDest = outputMessage + 8; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, textLength); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_LookupColor: - case X_AllocNamedColor: - { - unsigned int textLength; - decodeBuffer.decodeValue(textLength, 16, 6); - outputLength = 12 + RoundUp4(textLength); - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> colormapCache); - PutULONG(value, outputMessage + 4, bigEndian_); - PutUINT(textLength, outputMessage + 8, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, textLength); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_MapWindow: - case X_UnmapWindow: - case X_MapSubwindows: - case X_GetWindowAttributes: - case X_DestroyWindow: - case X_DestroySubwindows: - case X_QueryPointer: - case X_QueryTree: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - - if (outputOpcode == X_DestroyWindow) // Since ProtoStep7 (#issue 108) - { - decodeBuffer.decodeFreeXidValue(value, clientCache_ -> freeWindowCache); - } - else - { - decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); - } - - PutULONG(value, outputMessage + 4, bigEndian_); - if (outputOpcode == X_QueryPointer || - outputOpcode == X_GetWindowAttributes || - outputOpcode == X_QueryTree) - { - sequenceQueue_.push(clientSequence_, outputOpcode); - } - } - break; - case X_OpenFont: - { - unsigned int nameLength; - decodeBuffer.decodeValue(nameLength, 16, 7); - outputLength = RoundUp4(12 + nameLength); - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(nameLength, outputMessage + 8, bigEndian_); - decodeBuffer.decodeValue(value, 29, 5); - clientCache_ -> lastFont += value; - clientCache_ -> lastFont &= 0x1fffffff; - PutULONG(clientCache_ -> lastFont, outputMessage + 4, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeTextData(nextDest, nameLength); - } - break; - case X_PolyFillRectangle: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyFillRectangle); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 12; - outputMessage = writeBuffer_.addMessage(outputLength); - writeBuffer_.registerPointer(&outputMessage); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0, lastWidth = 0, lastHeight = 0; - unsigned int numRectangles = 0; - - for (;;) - { - outputLength += 8; - writeBuffer_.addMessage(8); - unsigned char *nextDest = outputMessage + 12 + - (numRectangles << 3); - numRectangles++; - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillRectangleCacheX[index], 8); - value += lastX; - PutUINT(value, nextDest, bigEndian_); - lastX = value; - nextDest += 2; - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillRectangleCacheY[index], 8); - value += lastY; - PutUINT(value, nextDest, bigEndian_); - lastY = value; - nextDest += 2; - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillRectangleCacheWidth[index], 8); - value += lastWidth; - PutUINT(value, nextDest, bigEndian_); - lastWidth = value; - nextDest += 2; - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillRectangleCacheHeight[index], 8); - value += lastHeight; - PutUINT(value, nextDest, bigEndian_); - lastHeight = value; - nextDest += 2; - - if (++index == 4) index = 0; - - decodeBuffer.decodeBoolValue(value); - - if (!value) break; - } - writeBuffer_.unregisterPointer(); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_PolyFillArc: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyFillArc); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 12; - outputMessage = writeBuffer_.addMessage(outputLength); - writeBuffer_.registerPointer(&outputMessage); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0, - lastWidth = 0, lastHeight = 0, - lastAngle1 = 0, lastAngle2 = 0; - - unsigned int numArcs = 0; - - for (;;) - { - outputLength += 12; - writeBuffer_.addMessage(12); - - unsigned char *nextDest = outputMessage + 12 + - (numArcs * 12); - numArcs++; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillArcCacheX[index], 8); - value += lastX; - PutUINT(value, nextDest, bigEndian_); - lastX = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillArcCacheY[index], 8); - value += lastY; - PutUINT(value, nextDest, bigEndian_); - lastY = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillArcCacheWidth[index], 8); - value += lastWidth; - PutUINT(value, nextDest, bigEndian_); - lastWidth = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillArcCacheHeight[index], 8); - value += lastHeight; - PutUINT(value, nextDest, bigEndian_); - lastHeight = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillArcCacheAngle1[index], 8); - value += lastAngle1; - PutUINT(value, nextDest, bigEndian_); - lastAngle1 = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyFillArcCacheAngle2[index], 8); - value += lastAngle2; - PutUINT(value, nextDest, bigEndian_); - lastAngle2 = value; - nextDest += 2; - - if (++index == 2) index = 0; - - decodeBuffer.decodeBoolValue(value); - - if (!value) break; - } - writeBuffer_.unregisterPointer(); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_PolyArc: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyArc); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - outputLength = 12; - outputMessage = writeBuffer_.addMessage(outputLength); - writeBuffer_.registerPointer(&outputMessage); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0, - lastWidth = 0, lastHeight = 0, - lastAngle1 = 0, lastAngle2 = 0; - - unsigned int numArcs = 0; - - for (;;) - { - outputLength += 12; - writeBuffer_.addMessage(12); - - unsigned char *nextDest = outputMessage + 12 + - (numArcs * 12); - numArcs++; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyArcCacheX[index], 8); - value += lastX; - PutUINT(value, nextDest, bigEndian_); - lastX = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyArcCacheY[index], 8); - value += lastY; - PutUINT(value, nextDest, bigEndian_); - lastY = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyArcCacheWidth[index], 8); - value += lastWidth; - PutUINT(value, nextDest, bigEndian_); - lastWidth = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyArcCacheHeight[index], 8); - value += lastHeight; - PutUINT(value, nextDest, bigEndian_); - lastHeight = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyArcCacheAngle1[index], 8); - value += lastAngle1; - PutUINT(value, nextDest, bigEndian_); - lastAngle1 = value; - nextDest += 2; - - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyArcCacheAngle2[index], 8); - value += lastAngle2; - PutUINT(value, nextDest, bigEndian_); - lastAngle2 = value; - nextDest += 2; - - if (++index == 2) index = 0; - - decodeBuffer.decodeBoolValue(value); - - if (!value) break; - } - writeBuffer_.unregisterPointer(); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_PolyPoint: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyPoint); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - unsigned int numPoints; - decodeBuffer.decodeValue(numPoints, 16, 4); - outputLength = (numPoints << 2) + 12; - outputMessage = writeBuffer_.addMessage(outputLength); - unsigned int relativeCoordMode; - decodeBuffer.decodeBoolValue(relativeCoordMode); - outputMessage[1] = (unsigned char) relativeCoordMode; - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0; - - for (unsigned int i = 0; i < numPoints; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyPointCacheX[index], 8); - lastX += value; - PutUINT(lastX, nextDest, bigEndian_); - nextDest += 2; - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyPointCacheY[index], 8); - lastY += value; - PutUINT(lastY, nextDest, bigEndian_); - nextDest += 2; - - if (++index == 2) index = 0; - } - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_PolyLine: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolyLine); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - unsigned int numPoints; - decodeBuffer.decodeValue(numPoints, 16, 4); - outputLength = (numPoints << 2) + 12; - outputMessage = writeBuffer_.addMessage(outputLength); - unsigned int relativeCoordMode; - decodeBuffer.decodeBoolValue(relativeCoordMode); - outputMessage[1] = (unsigned char) relativeCoordMode; - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - - unsigned int index = 0; - unsigned int lastX = 0, lastY = 0; - - for (unsigned int i = 0; i < numPoints; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyLineCacheX[index], 8); - lastX += value; - PutUINT(lastX, nextDest, bigEndian_); - nextDest += 2; - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyLineCacheY[index], 8); - lastY += value; - PutUINT(lastY, nextDest, bigEndian_); - nextDest += 2; - - if (++index == 2) index = 0; - } - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_PolyRectangle: - { - unsigned int numRectangles; - decodeBuffer.decodeValue(numRectangles, 16, 3); - outputLength = (numRectangles << 3) + 12; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - for (unsigned int i = 0; i < numRectangles; i++) - for (unsigned int k = 0; k < 4; k++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> polyRectangleGeomCache[k], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - } - break; - case X_PolySegment: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PolySegment); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - unsigned int numSegments; - decodeBuffer.decodeValue(numSegments, 16, 4); - outputLength = (numSegments << 3) + 12; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 8, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - - for (numSegments *= 2; numSegments; numSegments--) - { - unsigned int index; - decodeBuffer.decodeBoolValue(index); - unsigned int x; - decodeBuffer.decodeCachedValue(x, 16, - clientCache_ -> polySegmentCacheX, 6); - x += clientCache_ -> polySegmentLastX[index]; - PutUINT(x, nextDest, bigEndian_); - nextDest += 2; - - unsigned int y; - decodeBuffer.decodeCachedValue(y, 16, - clientCache_ -> polySegmentCacheY, 6); - y += clientCache_ -> polySegmentLastY[index]; - PutUINT(y, nextDest, bigEndian_); - nextDest += 2; - - clientCache_ -> polySegmentLastX[clientCache_ -> polySegmentCacheIndex] = x; - clientCache_ -> polySegmentLastY[clientCache_ -> polySegmentCacheIndex] = y; - - if (clientCache_ -> polySegmentCacheIndex == 1) - clientCache_ -> polySegmentCacheIndex = 0; - else - clientCache_ -> polySegmentCacheIndex = 1; - } - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_PutImage: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_PutImage); - - hit = handleDecode(decodeBuffer, clientCache_, messageStore, - outputOpcode, outputMessage, outputLength); - - if (outputOpcode == X_PutImage) - { - handleImage(outputOpcode, outputMessage, outputLength); - } - } - break; - case X_QueryBestSize: - { - outputLength = 12; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 2); - outputMessage[1] = (unsigned char)value; - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeValue(value, 16, 8); - PutUINT(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeValue(value, 16, 8); - PutUINT(value, outputMessage + 10, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_QueryColors: - { - // Differential or plain data compression? - decodeBuffer.decodeBoolValue(value); - - if (value) - { - unsigned int numColors; - decodeBuffer.decodeValue(numColors, 16, 5); - outputLength = (numColors << 2) + 8; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> colormapCache); - PutULONG(value, outputMessage + 4, bigEndian_); - unsigned char *nextDest = outputMessage + 8; - unsigned int predictedPixel = clientCache_ -> queryColorsLastPixel; - for (unsigned int i = 0; i < numColors; i++) - { - unsigned int pixel; - decodeBuffer.decodeBoolValue(value); - if (value) - pixel = predictedPixel; - else - decodeBuffer.decodeValue(pixel, 32, 9); - PutULONG(pixel, nextDest, bigEndian_); - if (i == 0) - clientCache_ -> queryColorsLastPixel = pixel; - predictedPixel = pixel + 1; - nextDest += 4; - } - } - else - { - // Request length. - unsigned int requestLength; - decodeBuffer.decodeValue(requestLength, 16, 10); - outputLength = (requestLength << 2); - outputMessage = writeBuffer_.addMessage(outputLength); - - const unsigned char *compressedData = NULL; - unsigned int compressedDataSize = 0; - - int decompressed = handleDecompress(decodeBuffer, outputOpcode, 4, - outputMessage, outputLength, compressedData, - compressedDataSize); - if (decompressed < 0) - { - return -1; - } - } - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_QueryExtension: - { - unsigned int nameLength; - decodeBuffer.decodeValue(nameLength, 16, 6); - outputLength = 8 + RoundUp4(nameLength); - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(nameLength, outputMessage + 4, bigEndian_); - unsigned char *nextDest = outputMessage + 8; - for (unsigned int i = 0; i < nameLength; i++) - { - decodeBuffer.decodeValue(value, 8); - *nextDest++ = (unsigned char) value; - } - - unsigned int hide = 0; - - #ifdef HIDE_MIT_SHM_EXTENSION - - if (!strncmp((char *) outputMessage + 8, "MIT-SHM", 7)) - { - #ifdef TEST - *logofs << "handleWrite: Going to hide MIT-SHM extension in reply.\n" - << logofs_flush; - #endif - - hide = 1; - } - - #endif - - #ifdef HIDE_BIG_REQUESTS_EXTENSION - - if (!strncmp((char *) outputMessage + 8, "BIG-REQUESTS", 12)) - { - #ifdef TEST - *logofs << "handleWrite: Going to hide BIG-REQUESTS extension in reply.\n" - << logofs_flush; - #endif - - hide = 1; - } - - #endif - - #ifdef HIDE_XKEYBOARD_EXTENSION - - else if (!strncmp((char *) outputMessage + 8, "XKEYBOARD", 9)) - { - #ifdef TEST - *logofs << "handleWrite: Going to hide XKEYBOARD extension in reply.\n" - << logofs_flush; - #endif - - hide = 1; - } - - #endif - - #ifdef HIDE_XFree86_Bigfont_EXTENSION - - else if (!strncmp((char *) outputMessage + 8, "XFree86-Bigfont", 15)) - { - #ifdef TEST - *logofs << "handleWrite: Going to hide XFree86-Bigfont extension in reply.\n" - << logofs_flush; - #endif - - hide = 1; - } - - #endif - - // - // This is if you want to experiment disabling SHAPE extensions. - // - - #ifdef HIDE_SHAPE_EXTENSION - - if (!strncmp((char *) outputMessage + 8, "SHAPE", 5)) - { - #ifdef DEBUG - *logofs << "handleWrite: Going to hide SHAPE extension in reply.\n" - << logofs_flush; - #endif - - hide = 1; - } - - #endif - - // - // Check if user disabled RENDER extension. - // - - if (control -> HideRender == 1 && - strncmp((char *) outputMessage + 8, "RENDER", 6) == 0) - { - #ifdef TEST - *logofs << "handleWrite: Going to hide RENDER extension in reply.\n" - << logofs_flush; - #endif - - hide = 1; - } - - unsigned int extension = 0; - - if (strncmp((char *) outputMessage + 8, "SHAPE", 5) == 0) - { - extension = X_NXInternalShapeExtension; - } - else if (strncmp((char *) outputMessage + 8, "RENDER", 6) == 0) - { - extension = X_NXInternalRenderExtension; - } - - sequenceQueue_.push(clientSequence_, outputOpcode, - outputOpcode, hide, extension); - } - break; - case X_QueryFont: - { - outputLength = 8; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 29, 5); - clientCache_ -> lastFont += value; - clientCache_ -> lastFont &= 0x1fffffff; - PutULONG(clientCache_ -> lastFont, outputMessage + 4, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_SetClipRectangles: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_SetClipRectangles); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - break; - } - - unsigned int numRectangles; - - // Since ProtoStep9 (#issue 108) - decodeBuffer.decodeValue(numRectangles, 15, 4); - - outputLength = (numRectangles << 3) + 12; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeValue(value, 2); - outputMessage[1] = (unsigned char) value; - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> setClipRectanglesXCache, 8); - PutUINT(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> setClipRectanglesYCache, 8); - PutUINT(value, outputMessage + 10, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - for (unsigned int i = 0; i < numRectangles; i++) - { - for (unsigned int k = 0; k < 4; k++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache_ -> setClipRectanglesGeomCache[k], 8); - PutUINT(value, nextDest, bigEndian_); - nextDest += 2; - } - } - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_SetDashes: - { - unsigned int numDashes; - decodeBuffer.decodeCachedValue(numDashes, 16, - clientCache_ -> setDashesLengthCache, 5); - outputLength = 12 + RoundUp4(numDashes); - outputMessage = writeBuffer_.addMessage(outputLength); - PutUINT(numDashes, outputMessage + 10, bigEndian_); - decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> setDashesOffsetCache, 5); - PutUINT(value, outputMessage + 8, bigEndian_); - unsigned char *nextDest = outputMessage + 12; - for (unsigned int i = 0; i < numDashes; i++) - { - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache_ -> setDashesDashCache_[i & 1], 5); - *nextDest++ = cValue; - } - } - break; - case X_SetSelectionOwner: - { - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> setSelectionOwnerCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> getSelectionOwnerSelectionCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 32, - clientCache_ -> setSelectionOwnerTimestampCache, 9); - PutULONG(value, outputMessage + 12, bigEndian_); - } - break; - case X_TranslateCoords: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_TranslateCoords); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - sequenceQueue_.push(clientSequence_, outputOpcode); - - break; - } - - outputLength = 16; - outputMessage = writeBuffer_.addMessage(outputLength); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> translateCoordsSrcCache, 9); - PutULONG(value, outputMessage + 4, bigEndian_); - decodeBuffer.decodeCachedValue(value, 29, - clientCache_ -> translateCoordsDstCache, 9); - PutULONG(value, outputMessage + 8, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> translateCoordsXCache, 8); - PutUINT(value, outputMessage + 12, bigEndian_); - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> translateCoordsYCache, 8); - PutUINT(value, outputMessage + 14, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_GetImage: - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_GetImage); - - if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, - outputMessage, outputLength)) - { - sequenceQueue_.push(clientSequence_, outputOpcode); - - break; - } - - outputLength = 20; - outputMessage = writeBuffer_.addMessage(outputLength); - // Format. - unsigned int format; - decodeBuffer.decodeValue(format, 2); - outputMessage[1] = (unsigned char) format; - // Drawable. - decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); - PutULONG(value, outputMessage + 4, bigEndian_); - // X. - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> putImageXCache, 8); - clientCache_ -> putImageLastX += value; - clientCache_ -> putImageLastX &= 0xffff; - PutUINT(clientCache_ -> putImageLastX, outputMessage + 8, bigEndian_); - // Y. - decodeBuffer.decodeCachedValue(value, 16, - clientCache_ -> putImageYCache, 8); - clientCache_ -> putImageLastY += value; - clientCache_ -> putImageLastY &= 0xffff; - PutUINT(clientCache_ -> putImageLastY, outputMessage + 10, bigEndian_); - // Width. - unsigned int width; - decodeBuffer.decodeCachedValue(width, 16, - clientCache_ -> putImageWidthCache, 8); - PutUINT(width, outputMessage + 12, bigEndian_); - // Height. - unsigned int height; - decodeBuffer.decodeCachedValue(height, 16, - clientCache_ -> putImageHeightCache, 8); - PutUINT(height, outputMessage + 14, bigEndian_); - // Plane mask. - decodeBuffer.decodeCachedValue(value, 32, - clientCache_ -> getImagePlaneMaskCache, 5); - PutULONG(value, outputMessage + 16, bigEndian_); - - sequenceQueue_.push(clientSequence_, outputOpcode); - - handleSave(messageStore, outputMessage, outputLength); - } - break; - case X_GetPointerMapping: - { - outputLength = 4; - outputMessage = writeBuffer_.addMessage(outputLength); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - case X_GetKeyboardControl: - { - outputLength = 4; - outputMessage = writeBuffer_.addMessage(outputLength); - - sequenceQueue_.push(clientSequence_, outputOpcode); - } - break; - default: - { - if (outputOpcode == opcodeStore_ -> renderExtension) - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXInternalRenderExtension); - - hit = handleDecode(decodeBuffer, clientCache_, messageStore, - outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> shapeExtension) - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXInternalShapeExtension); - - hit = handleDecode(decodeBuffer, clientCache_, messageStore, - outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> putPackedImage) - { - #ifdef DEBUG - *logofs << "handleWrite: Decoding packed image request for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXPutPackedImage); - - hit = handleDecode(decodeBuffer, clientCache_, messageStore, - outputOpcode, outputMessage, outputLength); - - if (outputOpcode == opcodeStore_ -> putPackedImage) - { - handleImage(outputOpcode, outputMessage, outputLength); - } - } - else if (outputOpcode == opcodeStore_ -> setUnpackColormap) - { - #ifdef DEBUG - *logofs << "handleWrite: Decoding set unpack colormap request " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXSetUnpackColormap); - - hit = handleDecode(decodeBuffer, clientCache_, messageStore, - outputOpcode, outputMessage, outputLength); - // - // Message could have been split. - // - - if (outputOpcode == opcodeStore_ -> setUnpackColormap) - { - handleColormap(outputOpcode, outputMessage, outputLength); - } - } - else if (outputOpcode == opcodeStore_ -> setUnpackAlpha) - { - #ifdef DEBUG - *logofs << "handleWrite: Decoding unpack alpha request for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXSetUnpackAlpha); - - hit = handleDecode(decodeBuffer, clientCache_, messageStore, - outputOpcode, outputMessage, outputLength); - // - // Message could have been split. - // - - if (outputOpcode == opcodeStore_ -> setUnpackAlpha) - { - handleAlpha(outputOpcode, outputMessage, outputLength); - } - } - else if (outputOpcode == opcodeStore_ -> setUnpackGeometry) - { - #ifdef DEBUG - *logofs << "handleWrite: Decoding set unpack geometry request " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXSetUnpackGeometry); - - hit = handleDecode(decodeBuffer, clientCache_, messageStore, - outputOpcode, outputMessage, outputLength); - - handleGeometry(outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> startSplit) - { - handleStartSplitRequest(decodeBuffer, outputOpcode, - outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> endSplit) - { - handleEndSplitRequest(decodeBuffer, outputOpcode, - outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> commitSplit) - { - int result = handleCommitSplitRequest(decodeBuffer, outputOpcode, - outputMessage, outputLength); - - // - // Check if message has been successfully - // extracted from the split store. In this - // case post-process it in the usual way. - // - - if (result > 0) - { - if (outputOpcode == opcodeStore_ -> putPackedImage || - outputOpcode == X_PutImage) - { - handleImage(outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> setUnpackColormap) - { - handleColormap(outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> setUnpackAlpha) - { - handleAlpha(outputOpcode, outputMessage, outputLength); - } - } - else if (result < 0) - { - return -1; - } - } - else if (outputOpcode == opcodeStore_ -> abortSplit) - { - handleAbortSplitRequest(decodeBuffer, outputOpcode, - outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> finishSplit) - { - #ifdef DEBUG - *logofs << "handleWrite: Decoding finish split request " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache_ -> resourceCache); - - handleNullRequest(outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> freeSplit) - { - #ifdef DEBUG - *logofs << "handleWrite: Decoding free split request " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache_ -> resourceCache); - - handleNullRequest(outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> freeUnpack) - { - #ifdef DEBUG - *logofs << "handleWrite: Decoding free unpack request " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache_ -> resourceCache); - - #ifdef DEBUG - *logofs << "handleWrite: Freeing unpack state for resource " - << (unsigned int) cValue << ".\n" << logofs_flush; - #endif - - handleUnpackStateRemove(cValue); - - handleNullRequest(outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> setExposeParameters) - { - // - // Send expose events according to agent's wish. - // - - decodeBuffer.decodeBoolValue(enableExpose_); - decodeBuffer.decodeBoolValue(enableGraphicsExpose_); - decodeBuffer.decodeBoolValue(enableNoExpose_); - - handleNullRequest(outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> getUnpackParameters) - { - // - // Client proxy needs the list of supported - // unpack methods. We would need an encode - // buffer, but this is in proxy, not here in - // channel. - // - - #ifdef TEST - *logofs << "handleWrite: Sending X_GetInputFocus request for FD#" - << fd_ << " due to OPCODE#" << (unsigned int) outputOpcode - << ".\n" << logofs_flush; - #endif - - outputOpcode = X_GetInputFocus; - - outputLength = 4; - outputMessage = writeBuffer_.addMessage(outputLength); - - sequenceQueue_.push(clientSequence_, outputOpcode, - opcodeStore_ -> getUnpackParameters); - } - else if (outputOpcode == opcodeStore_ -> getControlParameters || - outputOpcode == opcodeStore_ -> getCleanupParameters || - outputOpcode == opcodeStore_ -> getImageParameters) - { - handleNullRequest(outputOpcode, outputMessage, outputLength); - } - else if (outputOpcode == opcodeStore_ -> getShmemParameters) - { - if (handleShmemRequest(decodeBuffer, outputOpcode, - outputMessage, outputLength) < 0) - { - return -1; - } - } - else if (outputOpcode == opcodeStore_ -> setCacheParameters) - { - if (handleCacheRequest(decodeBuffer, outputOpcode, - outputMessage, outputLength) < 0) - { - return -1; - } - } - else if (outputOpcode == opcodeStore_ -> getFontParameters) - { - if (handleFontRequest(decodeBuffer, outputOpcode, - outputMessage, outputLength) < 0) - { - return -1; - } - } - else - { - MessageStore *messageStore = clientStore_ -> - getRequestStore(X_NXInternalGenericRequest); - - hit = handleDecode(decodeBuffer, clientCache_, messageStore, - outputOpcode, outputMessage, outputLength); - } - } - } // End of switch on opcode. - - // - // TODO: at the moment the variable hit was being set - // but not used, so to avoid the corresponding warning - // this logging block has been added. - // This code will probably be optimized away when none - // of the defines is set, but if there is no additional - // use for the hit variable in the future, then maybe - // it could be removed completely. - // - - if (hit) - { - #if defined(TEST) || defined(OPCODES) - *logofs << "handleWrite: Cached flag enabled in handled request.\n" - << logofs_flush; - #endif - } - - // - // A packed image request can generate more than just - // a single X_PutImage. Write buffer is handled inside - // handleUnpack(). Cannot simply assume that the final - // opcode and size must be put at the buffer offset as - // as buffer could have been grown or could have been - // replaced by a scratch buffer. The same is true in - // the case of a shared memory image. - // - - if (outputOpcode != 0) - { - // - // Commit opcode and size to the buffer. - // - - *outputMessage = (unsigned char) outputOpcode; - - PutUINT(outputLength >> 2, outputMessage + 2, bigEndian_); - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleWrite: Handled request OPCODE#" - << (unsigned int) outputOpcode << " (" - << DumpOpcode(outputOpcode) << ") for FD#" - << fd_ << " sequence " << clientSequence_ - << ". " << outputLength << " bytes out.\n" - << logofs_flush; - #endif - } - #if defined(TEST) || defined(OPCODES) - else - { - // - // In case of shared memory images the log doesn't - // reflect the actual opcode of the request that is - // going to be written. It would be possible to find - // the opcode of the original request received from - // the remote proxy in member imageState_ -> opcode, - // but we have probably already deleted the struct. - // - - *logofs << "handleWrite: Handled image request for FD#" - << fd_ << " new sequence " << clientSequence_ - << ". " << outputLength << " bytes out.\n" - << logofs_flush; - } - #endif - - // - // Check if we produced enough data. We need to - // decode all the proxy messages or the decode - // buffer will be left in an inconsistent state, - // so we just update the finish flag in case of - // failure. - // - - handleFlush(flush_if_needed); - - } // End of while (decodeBuffer.decodeOpcodeValue(outputOpcode, 8, ... - - } // End of the decoding block. - - // - // Write any remaining data to the X connection. - // - - if (handleFlush(flush_if_any) < 0) - { - return -1; - } - - // - // Reset offset at which we read the - // last event looking for the shared - // memory completion. - // - - if (shmemState_ != NULL) - { - shmemState_ -> checked = 0; - } - - return 1; -} - -// -// End of handleWrite(). -// - -// -// Other members. -// - -int ServerChannel::handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, - T_store_action action, int position, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - // Since ProtoStep7 (#issue 108) - splitState_.current = splitState_.resource; - - handleSplitStoreAlloc(&splitResources_, splitState_.current); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Message OPCODE#" - << (unsigned int) store -> opcode() << " of size " << size - << " [split] with resource " << splitState_.current - << " position " << position << " and action [" - << DumpAction(action) << "] at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - // - // Get the MD5 of the message being - // split. - // - - T_checksum checksum = NULL; - - if (action != IS_HIT) - { - handleSplitChecksum(decodeBuffer, checksum); - } - - // - // The method must abort the connection - // if it can't allocate the split. - // - - Split *splitMessage = clientStore_ -> getSplitStore(splitState_.current) -> - add(store, splitState_.current, position, - action, checksum, buffer, size); - - // - // If the encoding side didn't provide - // a checksum, then don't send the split - // report. - // - - if (checksum == NULL) - { - if (action == IS_HIT) - { - splitMessage -> setState(split_loaded); - } - else - { - splitMessage -> setState(split_missed); - } - - #if defined(TEST) || defined(SPLIT) - - *logofs << "handleSplit: SPLIT! There are " << clientStore_ -> - getSplitTotalSize() << " messages and " << clientStore_ -> - getSplitTotalStorageSize() << " bytes to send in " - << "the split stores.\n" << logofs_flush; - - clientStore_ -> dumpSplitStore(splitState_.current); - - #endif - - return 1; - } - - delete [] checksum; - - // - // Tell the split store if it must use - // the disk cache to retrieve and save - // the message. - // - - splitMessage -> setPolicy(splitState_.load, splitState_.save); - - // - // Try to locate the message on disk. - // - - if (clientStore_ -> getSplitStore(splitState_.current) -> - load(splitMessage) == 1) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Loaded the message " - << "from the image cache.\n" << logofs_flush; - #endif - - splitMessage -> setState(split_loaded); - } - else - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: WARNING! SPLIT! Can't find the message " - << "in the image cache.\n" << logofs_flush; - #endif - - splitMessage -> setState(split_missed); - } - - #if defined(TEST) || defined(SPLIT) - - T_timestamp startTs = getTimestamp(); - - *logofs << "handleSplit: SPLIT! Encoding abort " - << "split events for FD#" << fd_ << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - - if (proxy -> handleAsyncSplit(fd_, splitMessage) < 0) - { - return -1; - } - - // - // Send the encoded data immediately. We - // want the abort split message to reach - // the remote proxy as soon as possible. - // - - if (proxy -> handleAsyncFlush() < 0) - { - return -1; - } - - #if defined(TEST) || defined(SPLIT) - - *logofs << "handleSplit: SPLIT! Spent " - << diffTimestamp(startTs, getTimestamp()) << " Ms " - << "handling abort split events for FD#" << fd_ - << ".\n" << logofs_flush; - - *logofs << "handleSplit: SPLIT! There are " << clientStore_ -> - getSplitTotalSize() << " messages and " << clientStore_ -> - getSplitTotalStorageSize() << " bytes to send in " - << "the split stores.\n" << logofs_flush; - - clientStore_ -> dumpSplitStore(splitState_.current); - - #endif - - return 1; -} - -int ServerChannel::handleSplit(DecodeBuffer &decodeBuffer) -{ - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Going to handle splits " - << "for FD#" << fd_ << " at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - unsigned char resource; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeCachedValue(resource, 8, - clientCache_ -> resourceCache); - - splitState_.current = resource; - - handleSplitStoreAlloc(&splitResources_, splitState_.current); - - SplitStore *splitStore = clientStore_ -> getSplitStore(splitState_.current); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Handling splits for " - << "resource [" << splitState_.current << "] with " - << splitStore -> getSize() << " elements " - << "in the split store.\n" << logofs_flush; - #endif - - int result = splitStore -> receive(decodeBuffer); - - if (result < 0) - { - #ifdef PANIC - *logofs << "handleSplit: PANIC! Receive of split for FD#" << fd_ - << " failed.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Receive of split for FD#" << fd_ - << " failed.\n"; - - return -1; - } - else if (result == 0) - { - // - // The split is still incomplete. It's time - // to check if we need to start the house- - // keeping process to take care of the image - // cache. - // - - if (proxy -> handleAsyncKeeperCallback() < 0) - { - return -1; - } - } - else - { - // - // Note that we don't need the resource id at the - // X server side and, thus, we don't provide it - // at the time we add split to the split store. - // - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Remote agent should " - << "now commit a new split for resource [" - << splitState_.current << "].\n" - << logofs_flush; - - clientStore_ -> dumpCommitStore(); - - #endif - - if (splitStore -> getSize() == 0) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! Removing split store " - << "for resource [" << splitState_.current - << "] at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - handleSplitStoreRemove(&splitResources_, splitState_.current); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: SPLIT! There are [" << clientStore_ -> - getSplitTotalSize() << "] messages and " << clientStore_ -> - getSplitTotalStorageSize() << " bytes to send in " - << "the split stores.\n" << logofs_flush; - #endif - } - else - { - // - // If the next split is discarded, it can be - // that, since the beginning of the split, we - // have saved the message on the disk, due to - // a more recent split operation. This is also - // the case when we had to discard the message - // because it was locked but, since then, we - // completed the transferral of the split. - // - - Split *splitMessage = splitStore -> getFirstSplit(); - - if (splitMessage -> getAction() == is_discarded && - splitMessage -> getState() == split_missed && - splitStore -> load(splitMessage) == 1) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplit: WARNING! SPLIT! Asynchronously " - << "loaded the message from the image cache.\n" - << logofs_flush; - #endif - - splitMessage -> setState(split_loaded); - - #if defined(TEST) || defined(SPLIT) - - T_timestamp startTs = getTimestamp(); - - *logofs << "handleSplit: WARNING! SPLIT! Asynchronously " - << "encoding abort split events for FD#" << fd_ - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - if (proxy -> handleAsyncSplit(fd_, splitMessage) < 0) - { - return -1; - } - - // - // Send the encoded data immediately. We - // want the abort split message to reach - // the remote proxy as soon as possible. - // - - if (proxy -> handleAsyncFlush() < 0) - { - return -1; - } - - #if defined(TEST) || defined(SPLIT) - - *logofs << "handleSplit: WARNING! SPLIT! Spent " - << diffTimestamp(startTs, getTimestamp()) << " Ms " - << "handling asynchronous abort split events for " - << "FD#" << fd_ << ".\n" << logofs_flush; - - *logofs << "handleSplit: SPLIT! There are " << clientStore_ -> - getSplitTotalSize() << " messages and " << clientStore_ -> - getSplitTotalStorageSize() << " bytes to send in " - << "the split stores.\n" << logofs_flush; - - clientStore_ -> dumpSplitStore(splitState_.current); - - #endif - } - } - } - - return 1; -} - -int ServerChannel::handleSplitEvent(EncodeBuffer &encodeBuffer, Split *splitMessage) -{ - int resource = splitMessage -> getResource(); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitEvent: SPLIT! Going to send a " - << "split report for resource " << resource - << ".\n" << logofs_flush; - #endif - - // - // This function is called only after the message - // has been searched in the disk cache. We need to - // inform the other side if the data transfer can - // start or it must be aborted to let the local - // side use the copy that was found on the disk. - // - - #if defined(TEST) || defined(INFO) - - if (splitMessage -> getState() != split_loaded && - splitMessage -> getState() != split_missed) - { - *logofs << "handleSplitEvent: PANIC! Can't find the split to be aborted.\n" - << logofs_flush; - - HandleCleanup(); - } - - #endif - - // - // We need to send a boolean telling if the split - // was found or not, followed by the checksum of - // message we are referencing. - // - - T_checksum checksum = splitMessage -> getChecksum(); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitEvent: SPLIT! Sending split report for " - << "checksum [" << DumpChecksum(checksum) << "].\n" - << logofs_flush; - #endif - - if (proxy -> handleAsyncSwitch(fd_) < 0) - { - return -1; - } - - encodeBuffer.encodeOpcodeValue(opcodeStore_ -> splitEvent, - serverCache_ -> opcodeCache); - - // - // The encoding in older protocol versions - // is different but we will never try to - // send a split report if the remote does - // not support our version. - // - - encodeBuffer.encodeCachedValue(resource, 8, - serverCache_ -> resourceCache); - - if (splitMessage -> getState() == split_loaded) - { - encodeBuffer.encodeBoolValue(1); - - encodeBuffer.encodeOpcodeValue(splitMessage -> getStore() -> opcode(), - serverCache_ -> abortOpcodeCache); - - encodeBuffer.encodeValue(splitMessage -> compressedSize(), 32, 14); - } - else - { - encodeBuffer.encodeBoolValue(0); - } - - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - encodeBuffer.encodeValue((unsigned int) checksum[i], 8); - } - - // - // Update statistics for this special opcode. - // - - int bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) || defined(INFO) || defined(SPLIT) - *logofs << "handleSplitEvent: SPLIT! Handled event OPCODE#" - << (unsigned int) opcodeStore_ -> splitEvent << " (" - << DumpOpcode(opcodeStore_ -> splitEvent) << ")" << " for FD#" - << fd_ << " sequence none. 0 bytes in, " << bits << " bits (" - << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; - #endif - - statistics -> addEventBits(opcodeStore_ -> splitEvent, 0, bits); - - return 1; -} - -int ServerChannel::handleAbortSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - unsigned char resource; - - decodeBuffer.decodeCachedValue(resource, 8, - clientCache_ -> resourceCache); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleAbortSplitRequest: SPLIT! Handling abort split " - << "request for FD#" << fd_ << " and resource " - << (unsigned) resource << ".\n" - << logofs_flush; - #endif - - int splits = 0; - - SplitStore *splitStore = clientStore_ -> getSplitStore(resource); - - if (splitStore != NULL) - { - // - // Discard from the memory cache the messages - // that are still incomplete and then get rid - // of the splits in the store. - // - - #if defined(TEST) || defined(SPLIT) - - clientStore_ -> dumpSplitStore(resource); - - #endif - - Split *splitMessage; - - for (;;) - { - splitMessage = splitStore -> getFirstSplit(); - - if (splitMessage == NULL) - { - // - // Check if we had created the store - // but no message was added yet. - // - - #ifdef WARNING - - if (splits == 0) - { - *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The " - << "split store for resource [" << (unsigned int) - resource << "] is unexpectedly empty.\n" - << logofs_flush; - } - - #endif - - break; - } - - // - // Splits already aborted can't be in the - // split store. - // - - #if defined(TEST) || defined(SPLIT) - - if (splitMessage -> getState() == split_aborted) - { - *logofs << "handleAbortSplitRequest: PANIC! SPLIT! Found an " - << "aborted split in store [" << (unsigned int) resource - << "].\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - if (splitMessage -> getAction() == IS_HIT) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleAbortSplitRequest: SPLIT! Removing the " - << "split from the memory cache.\n" - << logofs_flush; - #endif - - splitMessage -> getStore() -> remove(splitMessage -> getPosition(), - discard_checksum, use_data); - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleAbortSplitRequest: SPLIT! Removing the " - << "split from the split store.\n" - << logofs_flush; - #endif - - splitMessage = splitStore -> pop(); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleAbortSplitRequest: SPLIT! Freeing up the " - << "aborted split.\n" << logofs_flush; - #endif - - delete splitMessage; - - splits++; - } - } - #ifdef WARNING - else - { - *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The " - << "split store for resource [" << (unsigned int) - resource << "] is already empty.\n" - << logofs_flush; - } - #endif - - handleNullRequest(opcode, buffer, size); - - return (splits > 0); -} - -int ServerChannel::handleCommitSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - // - // Get request type and position of the image - // to commit. - // - - unsigned char request; - - decodeBuffer.decodeOpcodeValue(request, clientCache_ -> opcodeCache); - - unsigned int diffCommit; - - decodeBuffer.decodeValue(diffCommit, 32, 5); - - splitState_.commit += diffCommit; - - unsigned char resource = 0; - unsigned int commit = 1; - - // - // Send the resource id and the commit flag. - // The resource id is ignored at the moment. - // The message will be handled based on the - // resource id that was sent together with - // the original message. - // - - decodeBuffer.decodeCachedValue(resource, 8, - clientCache_ -> resourceCache); - - decodeBuffer.decodeBoolValue(commit); - - Split *split = handleSplitCommitRemove(request, resource, splitState_.commit); - - if (split == NULL) - { - return -1; - } - - clientStore_ -> getCommitStore() -> update(split); - - if (commit == 1) - { - #if defined(TEST) || defined(SPLIT) - *logofs << "handleCommitSplitRequest: SPLIT! Handling split commit " - << "for FD#" << fd_ << " with commit " << commit - << " request " << (unsigned) request << " resource " - << (unsigned) resource << " and position " - << splitState_.commit << ".\n" - << logofs_flush; - #endif - - // - // Allocate as many bytes in the write - // buffer as the final length of the - // message in uncompressed form. - // - - size = split -> plainSize(); - - buffer = writeBuffer_.addMessage(size); - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleCommitSplitRequest: SPLIT! Prepared an " - << "outgoing buffer of " << size << " bytes.\n" - << logofs_flush; - #endif - - if (clientStore_ -> getCommitStore() -> expand(split, buffer, size) < 0) - { - writeBuffer_.removeMessage(size); - - commit = 0; - } - } - - // - // Free the split. - // - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleCommitSplitRequest: SPLIT! Freeing up the " - << "committed split.\n" << logofs_flush; - #endif - - delete split; - - // - // Discard the operation and send a null - // message. - // - - if (commit == 0) - { - handleNullRequest(opcode, buffer, size); - } - else - { - // - // Save the sequence number to be able - // to mask any error generated by the - // request. - // - - updateCommitQueue(clientSequence_); - - // - // Now in the write buffer there is - // a copy of this request. - // - - opcode = request; - } - - return commit; -} - -int ServerChannel::handleGeometry(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size) -{ - // - // Replace the old geometry and taint - // the message into a X_NoOperation. - // - - int resource = *(buffer + 1); - - #ifdef TEST - *logofs << "handleGeometry: Setting new unpack geometry " - << "for resource " << resource << ".\n" - << logofs_flush; - #endif - - handleUnpackStateInit(resource); - - handleUnpackAllocGeometry(resource); - - unpackState_[resource] -> geometry -> depth1_bpp = *(buffer + 4); - unpackState_[resource] -> geometry -> depth4_bpp = *(buffer + 5); - unpackState_[resource] -> geometry -> depth8_bpp = *(buffer + 6); - unpackState_[resource] -> geometry -> depth16_bpp = *(buffer + 7); - unpackState_[resource] -> geometry -> depth24_bpp = *(buffer + 8); - unpackState_[resource] -> geometry -> depth32_bpp = *(buffer + 9); - - unpackState_[resource] -> geometry -> red_mask = GetULONG(buffer + 12, bigEndian_); - unpackState_[resource] -> geometry -> green_mask = GetULONG(buffer + 16, bigEndian_); - unpackState_[resource] -> geometry -> blue_mask = GetULONG(buffer + 20, bigEndian_); - - handleCleanAndNullRequest(opcode, buffer, size); - - return 1; -} - -int ServerChannel::handleColormap(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size) -{ - // - // Replace the old colormap and taint - // the message into a X_NoOperation. - // - - int resource = *(buffer + 1); - - #ifdef TEST - *logofs << "handleColormap: Setting new unpack colormap " - << "for resource " << resource << ".\n" - << logofs_flush; - #endif - - handleUnpackStateInit(resource); - - handleUnpackAllocColormap(resource); - - // - // New protocol versions send the alpha - // data in compressed form. - // - - // - // Since ProtoStep7 (#issue 108) - // - - { // An anonymous block is used here to limit the scope of local variables - unsigned int packed = GetULONG(buffer + 8, bigEndian_); - unsigned int unpacked = GetULONG(buffer + 12, bigEndian_); - - validateSize("colormap", packed, unpacked, 16, size); - - if (unpackState_[resource] -> colormap -> entries != unpacked >> 2 && - unpackState_[resource] -> colormap -> data != NULL) - { - #ifdef TEST - *logofs << "handleColormap: Freeing previously allocated " - << "unpack colormap data.\n" << logofs_flush; - #endif - - delete [] unpackState_[resource] -> colormap -> data; - - unpackState_[resource] -> colormap -> data = NULL; - unpackState_[resource] -> colormap -> entries = 0; - } - - #ifdef TEST - *logofs << "handleColormap: Setting " << unpacked - << " bytes of unpack colormap data for resource " - << resource << ".\n" << logofs_flush; - #endif - - if (unpackState_[resource] -> colormap -> data == NULL) - { - unpackState_[resource] -> colormap -> data = - (unsigned int *) new unsigned char[unpacked]; - - if (unpackState_[resource] -> colormap -> data == NULL) - { - #ifdef PANIC - *logofs << "handleColormap: PANIC! Can't allocate " - << unpacked << " entries for unpack colormap data " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - goto handleColormapEnd; - } - - #ifdef DEBUG - *logofs << "handleColormap: Size of new colormap data is " - << unpacked << ".\n" << logofs_flush; - #endif - } - - unsigned int method = *(buffer + 4); - - if (method == PACK_COLORMAP) - { - if (UnpackColormap(method, buffer + 16, packed, - (unsigned char *) unpackState_[resource] -> - colormap -> data, unpacked) < 0) - { - #ifdef PANIC - *logofs << "handleColormap: PANIC! Can't unpack " << packed - << " bytes to " << unpacked << " entries for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - delete [] unpackState_[resource] -> colormap -> data; - - unpackState_[resource] -> colormap -> data = NULL; - unpackState_[resource] -> colormap -> entries = 0; - - goto handleColormapEnd; - } - } - else - { - memcpy((unsigned char *) unpackState_[resource] -> - colormap -> data, buffer + 16, unpacked); - } - - unpackState_[resource] -> colormap -> entries = unpacked >> 2; - - #if defined(DEBUG) && defined(DUMP) - - *logofs << "handleColormap: Dumping colormap entries:\n" - << logofs_flush; - - const unsigned char *p = (const unsigned char *) unpackState_[resource] -> colormap -> data; - - for (unsigned int i = 0; i < unpackState_[resource] -> - colormap -> entries; i++) - { - *logofs << "handleColormap: [" << i << "] [" - << (void *) ((int) p[i]) << "].\n" - << logofs_flush; - } - - #endif - } // end anonymous block - -handleColormapEnd: - - handleCleanAndNullRequest(opcode, buffer, size); - - return 1; -} - -int ServerChannel::handleAlpha(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size) -{ - int resource = *(buffer + 1); - - #ifdef TEST - *logofs << "handleAlpha: Setting new unpack alpha " - << "for resource " << resource << ".\n" - << logofs_flush; - #endif - - handleUnpackStateInit(resource); - - handleUnpackAllocAlpha(resource); - - // - // New protocol versions send the alpha - // data in compressed form. - // - - // - // Since ProtoStep7 (#issue 108) - // - - { // An anonymous block is used here to limit the scope of local variables - unsigned int packed = GetULONG(buffer + 8, bigEndian_); - unsigned int unpacked = GetULONG(buffer + 12, bigEndian_); - - validateSize("alpha", packed, unpacked, 16, size); - - if (unpackState_[resource] -> alpha -> entries != unpacked && - unpackState_[resource] -> alpha -> data != NULL) - { - #ifdef TEST - *logofs << "handleAlpha: Freeing previously allocated " - << "unpack alpha data.\n" << logofs_flush; - #endif - - delete [] unpackState_[resource] -> alpha -> data; - - unpackState_[resource] -> alpha -> data = NULL; - unpackState_[resource] -> alpha -> entries = 0; - } - - #ifdef TEST - *logofs << "handleAlpha: Setting " << unpacked - << " bytes of unpack alpha data for resource " - << resource << ".\n" << logofs_flush; - #endif - - if (unpackState_[resource] -> alpha -> data == NULL) - { - unpackState_[resource] -> alpha -> data = new unsigned char[unpacked]; - - if (unpackState_[resource] -> alpha -> data == NULL) - { - #ifdef PANIC - *logofs << "handleAlpha: PANIC! Can't allocate " - << unpacked << " entries for unpack alpha data " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - goto handleAlphaEnd; - } - - #ifdef DEBUG - *logofs << "handleAlpha: Size of new alpha data is " - << unpacked << ".\n" << logofs_flush; - #endif - } - - unsigned int method = *(buffer + 4); - - if (method == PACK_ALPHA) - { - if (UnpackAlpha(method, buffer + 16, packed, - unpackState_[resource] -> alpha -> - data, unpacked) < 0) - { - #ifdef PANIC - *logofs << "handleAlpha: PANIC! Can't unpack " << packed - << " bytes to " << unpacked << " entries for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - delete [] unpackState_[resource] -> alpha -> data; - - unpackState_[resource] -> alpha -> data = NULL; - unpackState_[resource] -> alpha -> entries = 0; - - goto handleAlphaEnd; - } - } - else - { - memcpy((unsigned char *) unpackState_[resource] -> - alpha -> data, buffer + 16, unpacked); - } - - unpackState_[resource] -> alpha -> entries = unpacked; - - #if defined(DEBUG) && defined(DUMP) - - *logofs << "handleAlpha: Dumping alpha entries:\n" - << logofs_flush; - - const unsigned char *p = unpackState_[resource] -> alpha -> data; - - for (unsigned int i = 0; i < unpackState_[resource] -> - alpha -> entries; i++) - { - *logofs << "handleAlpha: [" << i << "] [" - << (void *) ((int) p[i]) << "].\n" - << logofs_flush; - } - - #endif - } //end anonymous block - -handleAlphaEnd: - - handleCleanAndNullRequest(opcode, buffer, size); - - return 1; -} - -int ServerChannel::handleImage(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size) -{ - int result = 1; - - // - // Save the original opcode together with - // the image state so we can later find if - // this is a plain or a packed image when - // moving data to the shared memory area. - // - - handleImageStateAlloc(opcode); - - if (opcode == opcodeStore_ -> putPackedImage) - { - // - // Unpack the image and put a X_PutImage in a - // new buffer. Save the expected output size, - // so, in the case of a decoding error we can - // still update the statistics. - // - - int length = GetULONG(buffer + 20, bigEndian_); - - #ifdef TEST - *logofs << "handleImage: Sending image for FD#" << fd_ - << " due to OPCODE#" << (unsigned int) opcode << " with " - << GetULONG(buffer + 16, bigEndian_) << " bytes packed " - << "and " << GetULONG(buffer + 20, bigEndian_) - << " bytes unpacked.\n" << logofs_flush; - #endif - - statistics -> addPackedBytesIn(size); - - result = handleUnpack(opcode, buffer, size); - - if (result < 0) - { - // - // Recover from the error. Send a X_NoOperation - // to keep the sequence counter in sync with - // the remote peer. - // - - size = 4; - buffer = writeBuffer_.addMessage(size); - - *buffer = X_NoOperation; - - PutUINT(size >> 2, buffer + 2, bigEndian_); - - #ifdef PANIC - *logofs << "handleImage: PANIC! Sending X_NoOperation for FD#" - << fd_ << " to recover from failed unpack.\n" - << logofs_flush; - #endif - - // - // Set the output length to reflect the amount of - // data that would have been produced by unpacking - // the image. This is advisable to keep the count- - // ers in sync with those at remote proxy. Setting - // the size here doesn't have any effect on the - // size of data sent to the X server as the actual - // size will be taken from the content of the write - // buffer. - // - - size = length; - } - - statistics -> addPackedBytesOut(size); - - // - // Refrain the write loop from putting - // opcode and size in the output buffer. - // - - opcode = 0; - } - - // - // Now image is unpacked as a X_PutImage - // in write buffer. Check if we can send - // the image using the MIT-SHM extension. - // - - if (result > 0) - { - result = handleShmem(opcode, buffer, size); - - // - // We already put opcode and size in - // the resulting buffer. - // - - if (result > 0) - { - opcode = 0; - } - } - - return 1; -} - -int ServerChannel::handleMotion(EncodeBuffer &encodeBuffer) -{ - #if defined(TEST) || defined(INFO) - - if (lastMotion_[0] == '\0') - { - *logofs << "handleMotion: PANIC! No motion events to send " - << "for FD#" << fd_ << ".\n" << logofs_flush; - - HandleCleanup(); - } - - #endif - - #if defined(TEST) || defined(INFO) - *logofs << "handleMotion: Sending motion events for FD#" - << fd_ << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - // - // Replicate code from read loop. When have - // time and wish, try to split everything - // in functions. - // - - if (proxy -> handleAsyncSwitch(fd_) < 0) - { - return -1; - } - - const unsigned char *buffer = lastMotion_; - unsigned char opcode = *lastMotion_; - unsigned int size = 32; - - if (GetUINT(buffer + 2, bigEndian_) < serverSequence_) - { - PutUINT(serverSequence_, (unsigned char *) buffer + 2, bigEndian_); - } - - encodeBuffer.encodeOpcodeValue(opcode, serverCache_ -> opcodeCache); - - unsigned int sequenceNum = GetUINT(buffer + 2, bigEndian_); - - unsigned int sequenceDiff = sequenceNum - serverSequence_; - - serverSequence_ = sequenceNum; - - #ifdef DEBUG - *logofs << "handleMotion: Last server sequence number for FD#" - << fd_ << " is " << serverSequence_ << " with " - << "difference " << sequenceDiff << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(sequenceDiff, 16, - serverCache_ -> eventSequenceCache, 7); - - // - // If we fast encoded the message - // then skip the rest. - // - - if (control -> LocalDeltaCompression == 0) - { - int result = handleFastReadEvent(encodeBuffer, opcode, - buffer, size); - - #ifdef DEBUG - *logofs << "handleMotion: Sent saved motion event for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - lastMotion_[0] = '\0'; - - #ifdef DEBUG - *logofs << "handleMotion: Reset last motion event for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - if (result < 0) - { - return -1; - } - else if (result > 0) - { - return 1; - } - } - - // - // This should be just the part specific - // for motion events but is currently a - // copy-paste of code from the read loop. - // - - unsigned char detail = buffer[1]; - if (*buffer == MotionNotify) - encodeBuffer.encodeBoolValue((unsigned int) detail); - else if ((*buffer == EnterNotify) || (*buffer == LeaveNotify)) - encodeBuffer.encodeValue((unsigned int) detail, 3); - else if (*buffer == KeyRelease) - { - if (detail == serverCache_ -> keyPressLastKey) - encodeBuffer.encodeBoolValue(1); - else - { - encodeBuffer.encodeBoolValue(0); - encodeBuffer.encodeValue((unsigned int) detail, 8); - } - } - else if ((*buffer == ButtonPress) || (*buffer == ButtonRelease)) - encodeBuffer.encodeCachedValue(detail, 8, - serverCache_ -> buttonCache); - else - encodeBuffer.encodeValue((unsigned int) detail, 8); - unsigned int timestamp = GetULONG(buffer + 4, bigEndian_); - unsigned int timestampDiff = timestamp - serverCache_ -> lastTimestamp; - serverCache_ -> lastTimestamp = timestamp; - encodeBuffer.encodeCachedValue(timestampDiff, 32, - serverCache_ -> motionNotifyTimestampCache, 9); - int skipRest = 0; - if (*buffer == KeyRelease) - { - skipRest = 1; - for (unsigned int i = 8; i < 31; i++) - { - if (buffer[i] != serverCache_ -> keyPressCache[i - 8]) - { - skipRest = 0; - break; - } - } - encodeBuffer.encodeBoolValue(skipRest); - } - if (!skipRest) - { - const unsigned char *nextSrc = buffer + 8; - for (unsigned int i = 0; i < 3; i++) - { - encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29, - *serverCache_ -> motionNotifyWindowCache[i], 6); - nextSrc += 4; - } - unsigned int rootX = GetUINT(buffer + 20, bigEndian_); - unsigned int rootY = GetUINT(buffer + 22, bigEndian_); - unsigned int eventX = GetUINT(buffer + 24, bigEndian_); - unsigned int eventY = GetUINT(buffer + 26, bigEndian_); - eventX -= rootX; - eventY -= rootY; - encodeBuffer.encodeCachedValue(rootX - - serverCache_ -> motionNotifyLastRootX, 16, - serverCache_ -> motionNotifyRootXCache, 6); - serverCache_ -> motionNotifyLastRootX = rootX; - encodeBuffer.encodeCachedValue(rootY - - serverCache_ -> motionNotifyLastRootY, 16, - serverCache_ -> motionNotifyRootYCache, 6); - serverCache_ -> motionNotifyLastRootY = rootY; - encodeBuffer.encodeCachedValue(eventX, 16, - serverCache_ -> motionNotifyEventXCache, 6); - encodeBuffer.encodeCachedValue(eventY, 16, - serverCache_ -> motionNotifyEventYCache, 6); - encodeBuffer.encodeCachedValue(GetUINT(buffer + 28, bigEndian_), - 16, serverCache_ -> motionNotifyStateCache); - if ((*buffer == EnterNotify) || (*buffer == LeaveNotify)) - encodeBuffer.encodeValue((unsigned int) buffer[30], 2); - else - encodeBuffer.encodeBoolValue((unsigned int) buffer[30]); - if ((*buffer == EnterNotify) || (*buffer == LeaveNotify)) - encodeBuffer.encodeValue((unsigned int) buffer[31], 2); - else if (*buffer == KeyPress) - { - serverCache_ -> keyPressLastKey = detail; - for (unsigned int i = 8; i < 31; i++) - { - serverCache_ -> keyPressCache[i - 8] = buffer[i]; - } - } - } - - // - // Print info about achieved compression - // and update the statistics. - // - - int bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleMotion: Handled event OPCODE#" << (unsigned int) buffer[0] - << " for FD#" << fd_ << " sequence " << sequenceNum << ". " - << size << " bytes in, " << bits << " bits (" << ((float) bits) / 8 - << " bytes) out.\n" << logofs_flush; - #endif - - statistics -> addEventBits(*buffer, size << 3, bits); - - #ifdef DEBUG - *logofs << "handleMotion: Sent saved motion event for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - lastMotion_[0] = '\0'; - - #ifdef DEBUG - *logofs << "handleMotion: Reset last motion event for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - return 1; -} - -int ServerChannel::handleConfiguration() -{ - #ifdef TEST - *logofs << "ServerChannel: Setting new buffer parameters " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - readBuffer_.setSize(control -> ServerInitialReadSize, - control -> ServerMaximumBufferSize); - - writeBuffer_.setSize(control -> TransportXBufferSize, - control -> TransportXBufferThreshold, - control -> TransportMaximumBufferSize); - - transport_ -> setSize(control -> TransportXBufferSize, - control -> TransportXBufferThreshold, - control -> TransportMaximumBufferSize); - return 1; -} - -int ServerChannel::handleFinish() -{ - #ifdef TEST - *logofs << "ServerChannel: Finishing connection for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - congestion_ = 0; - priority_ = 0; - - finish_ = 1; - - // - // Reset the motion event. - // - - lastMotion_[0] = '\0'; - - transport_ -> fullReset(); - - return 1; -} - -int ServerChannel::handleAsyncEvents() -{ - // - // Encode more events while decoding the - // proxy messages. - // - - if (transport_ -> readable() > 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleAsyncEvents: WARNING! Encoding events " - << "for FD#" << fd_ << " at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - #if defined(TEST) || defined(INFO) - - T_timestamp startTs = getTimestamp(); - - #endif - - if (proxy -> handleAsyncRead(fd_) < 0) - { - return -1; - } - - #if defined(TEST) || defined(INFO) - *logofs << "handleAsyncEvents: Spent " << diffTimestamp(startTs, - getTimestamp()) << " Ms handling events for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - return 1; - } - - return 0; -} - -int ServerChannel::handleUnpack(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size) -{ - int resource = *(buffer + 1); - - #ifdef DEBUG - *logofs << "handleUnpack: Unpacking image for resource " << resource - << " with method " << (unsigned int) *(buffer + 12) - << ".\n" << logofs_flush; - #endif - - handleUnpackStateInit(resource); - - T_geometry *geometryState = unpackState_[resource] -> geometry; - T_colormap *colormapState = unpackState_[resource] -> colormap; - T_alpha *alphaState = unpackState_[resource] -> alpha; - - if (geometryState == NULL) - { - #ifdef PANIC - *logofs << "handleUnpack: PANIC! Missing geometry unpacking " - << "image for resource " << resource << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Missing geometry unpacking " - << "image for resource " << resource << ".\n"; - - return -1; - } - - // - // Get the image data from the buffer. - // - - imageState_ -> drawable = GetULONG(buffer + 4, bigEndian_); - imageState_ -> gcontext = GetULONG(buffer + 8, bigEndian_); - - imageState_ -> method = *(buffer + 12); - - imageState_ -> format = *(buffer + 13); - imageState_ -> srcDepth = *(buffer + 14); - imageState_ -> dstDepth = *(buffer + 15); - - imageState_ -> srcLength = GetULONG(buffer + 16, bigEndian_); - imageState_ -> dstLength = GetULONG(buffer + 20, bigEndian_); - - imageState_ -> srcX = GetUINT(buffer + 24, bigEndian_); - imageState_ -> srcY = GetUINT(buffer + 26, bigEndian_); - imageState_ -> srcWidth = GetUINT(buffer + 28, bigEndian_); - imageState_ -> srcHeight = GetUINT(buffer + 30, bigEndian_); - - imageState_ -> dstX = GetUINT(buffer + 32, bigEndian_); - imageState_ -> dstY = GetUINT(buffer + 34, bigEndian_); - imageState_ -> dstWidth = GetUINT(buffer + 36, bigEndian_); - imageState_ -> dstHeight = GetUINT(buffer + 38, bigEndian_); - - #ifdef TEST - *logofs << "handleUnpack: Source X is " << imageState_ -> srcX - << " Y is " << imageState_ -> srcY << " width is " - << imageState_ -> srcWidth << " height is " - << imageState_ -> srcHeight << ".\n" - << logofs_flush; - #endif - - #ifdef TEST - *logofs << "handleUnpack: Destination X is " << imageState_ -> dstX - << " Y is " << imageState_ -> dstY << " width is " - << imageState_ -> dstWidth << " height is " - << imageState_ -> dstHeight << ".\n" - << logofs_flush; - #endif - - if (imageState_ -> srcX != 0 || imageState_ -> srcY != 0) - { - #ifdef PANIC - *logofs << "handleUnpack: PANIC! Unsupported source coordinates " - << "in unpack request.\n" << logofs_flush; - #endif - - return -1; - } - else if (imageState_ -> method == PACK_COLORMAP_256_COLORS && - (colormapState == NULL || colormapState -> data == NULL)) - { - #ifdef PANIC - *logofs << "handleUnpack: PANIC! Cannot find any unpack colormap.\n" - << logofs_flush; - #endif - - return -1; - } - - // - // Field srcLength carries size of image data in - // packed format. Field dstLength is size of the - // image in the original X bitmap format. - // - - unsigned int srcDataOffset = 40; - - unsigned int srcSize = imageState_ -> srcLength; - - unsigned int removeSize = size; - - unsigned char *srcData = buffer + srcDataOffset; - - // - // Get source and destination bits per pixel. - // - - int srcBitsPerPixel = MethodBitsPerPixel(imageState_ -> method); - - if (srcBitsPerPixel <= 0) - { - #ifdef PANIC - *logofs << "handleUnpack: PANIC! Can't identify source " - << "bits per pixel for method " << (unsigned int) - imageState_ -> method << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify source bits " - << "per pixel for method " << (unsigned int) - imageState_ -> method << ".\n"; - - writeBuffer_.removeMessage(removeSize); - - return -1; - } - - #ifdef TEST - *logofs << "handleUnpack: Source bits per pixel are " - << srcBitsPerPixel << " source data size is " - << srcSize << ".\n" << logofs_flush; - #endif - - int dstBitsPerPixel = UnpackBitsPerPixel(geometryState, imageState_ -> dstDepth); - - if (dstBitsPerPixel <= 0) - { - #ifdef PANIC - *logofs << "handleUnpack: PANIC! Can't identify " - << "destination bits per pixel for depth " - << (unsigned int) imageState_ -> dstDepth - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't identify " - << "destination bits per pixel for depth " - << (unsigned int) imageState_ -> dstDepth - << ".\n"; - - writeBuffer_.removeMessage(removeSize); - - return -1; - } - - // - // Destination is a PutImage request. - // - - unsigned int dstDataOffset = 24; - - // - // Output buffer size must match the number of input - // pixels multiplied by the number of bytes per pixel - // of current geometry. - // - - size = (RoundUp4(imageState_ -> dstWidth * dstBitsPerPixel / 8) * - imageState_ -> dstHeight) + dstDataOffset; - - #ifdef TEST - *logofs << "handleUnpack: Destination bits per pixel are " - << dstBitsPerPixel << " destination data size is " - << size - dstDataOffset << ".\n" << logofs_flush; - #endif - - unsigned int dstSize = size - dstDataOffset; - - imageState_ -> dstLines = imageState_ -> dstHeight; - - unsigned char *dstData; - - // - // Size of the final output buffer had to be stored - // in the offset field of XImage/NXPackedImage. - // - - #ifdef WARNING - - if (dstSize != imageState_ -> dstLength) - { - *logofs << "handleUnpack: WARNING! Destination size mismatch " - << "with reported " << imageState_ -> dstLength - << " and actual " << dstSize << ".\n" - << logofs_flush; - } - - #endif - - // - // The decoding algorithm has put the packed image - // in the plain write buffer. Let's use the scratch - // buffer to uncompress the image. - // - - buffer = writeBuffer_.addScratchMessage(size); - - dstData = buffer + dstDataOffset; - - // - // Unpack image into the buffer. - // - - *buffer = (unsigned char) X_PutImage; - - *(buffer + 1) = imageState_ -> format; - - PutUINT(size >> 2, buffer + 2, bigEndian_); - - PutULONG(imageState_ -> drawable, buffer + 4, bigEndian_); - PutULONG(imageState_ -> gcontext, buffer + 8, bigEndian_); - - PutUINT(imageState_ -> dstWidth, buffer + 12, bigEndian_); - PutUINT(imageState_ -> dstLines, buffer + 14, bigEndian_); - - PutUINT(imageState_ -> dstX, buffer + 16, bigEndian_); - PutUINT(imageState_ -> dstY, buffer + 18, bigEndian_); - - *(buffer + 20) = 0; - *(buffer + 21) = imageState_ -> dstDepth; - - #ifdef TEST - *logofs << "handleUnpack: Write buffer size is " - << writeBuffer_.getLength() << " scratch size is " - << writeBuffer_.getScratchLength() << ".\n" - << logofs_flush; - #endif - - int result = 0; - - switch (imageState_ -> method) - { - case PACK_JPEG_8_COLORS: - case PACK_JPEG_64_COLORS: - case PACK_JPEG_256_COLORS: - case PACK_JPEG_512_COLORS: - case PACK_JPEG_4K_COLORS: - case PACK_JPEG_32K_COLORS: - case PACK_JPEG_64K_COLORS: - case PACK_JPEG_256K_COLORS: - case PACK_JPEG_2M_COLORS: - case PACK_JPEG_16M_COLORS: - { - result = UnpackJpeg(geometryState, imageState_ -> method, srcData, - srcSize, dstBitsPerPixel, imageState_ -> dstWidth, - imageState_ -> dstHeight, dstData, dstSize); - break; - } - case PACK_PNG_8_COLORS: - case PACK_PNG_64_COLORS: - case PACK_PNG_256_COLORS: - case PACK_PNG_512_COLORS: - case PACK_PNG_4K_COLORS: - case PACK_PNG_32K_COLORS: - case PACK_PNG_64K_COLORS: - case PACK_PNG_256K_COLORS: - case PACK_PNG_2M_COLORS: - case PACK_PNG_16M_COLORS: - { - result = UnpackPng(geometryState, imageState_ -> method, srcData, - srcSize, dstBitsPerPixel, imageState_ -> dstWidth, - imageState_ -> dstHeight, dstData, dstSize); - break; - } - case PACK_RGB_16M_COLORS: - { - result = UnpackRgb(geometryState, imageState_ -> method, srcData, - srcSize, dstBitsPerPixel, imageState_ -> dstWidth, - imageState_ -> dstHeight, dstData, dstSize); - break; - } - case PACK_RLE_16M_COLORS: - { - result = UnpackRle(geometryState, imageState_ -> method, srcData, - srcSize, dstBitsPerPixel, imageState_ -> dstWidth, - imageState_ -> dstHeight, dstData, dstSize); - break; - } - case PACK_BITMAP_16M_COLORS: - { - result = UnpackBitmap(geometryState, imageState_ -> method, srcData, - srcSize, dstBitsPerPixel, imageState_ -> dstWidth, - imageState_ -> dstHeight, dstData, dstSize); - break; - } - case PACK_COLORMAP_256_COLORS: - { - result = Unpack8(geometryState, colormapState, srcBitsPerPixel, - imageState_ -> srcWidth, imageState_ -> srcHeight, srcData, - srcSize, dstBitsPerPixel, imageState_ -> dstWidth, - imageState_ -> dstHeight, dstData, dstSize); - - break; - } - default: - { - const T_colormask *colorMask = MethodColorMask(imageState_ -> method); - - switch (imageState_ -> method) - { - case PACK_MASKED_8_COLORS: - case PACK_MASKED_64_COLORS: - case PACK_MASKED_256_COLORS: - { - result = Unpack8(geometryState, colorMask, imageState_ -> srcDepth, - imageState_ -> srcWidth, imageState_ -> srcHeight, - srcData, srcSize, imageState_ -> dstDepth, - imageState_ -> dstWidth, imageState_ -> dstHeight, - dstData, dstSize); - break; - } - case PACK_MASKED_512_COLORS: - case PACK_MASKED_4K_COLORS: - case PACK_MASKED_32K_COLORS: - case PACK_MASKED_64K_COLORS: - { - result = Unpack16(geometryState, colorMask, imageState_ -> srcDepth, - imageState_ -> srcWidth, imageState_ -> srcHeight, - srcData, srcSize, imageState_ -> dstDepth, - imageState_ -> dstWidth, imageState_ -> dstHeight, - dstData, dstSize); - break; - } - case PACK_MASKED_256K_COLORS: - case PACK_MASKED_2M_COLORS: - case PACK_MASKED_16M_COLORS: - { - result = Unpack24(geometryState, colorMask, imageState_ -> srcDepth, - imageState_ -> srcWidth, imageState_ -> srcHeight, - srcData, srcSize, imageState_ -> dstDepth, - imageState_ -> dstWidth, imageState_ -> dstHeight, - dstData, dstSize); - break; - } - default: - { - break; - } - } - } - } - - writeBuffer_.removeMessage(removeSize); - - if (result <= 0) - { - #ifdef PANIC - *logofs << "handleUnpack: PANIC! Failed to unpack image " - << "with method '" << (unsigned int) imageState_ -> method - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Failed to unpack image " - << "with method '" << (unsigned int) imageState_ -> method - << "'.\n"; - - // - // TODO: We should mark the image somehow, - // and force the remote to remove it from - // the cache. - // - - writeBuffer_.removeScratchMessage(); - - return -1; - } - - // - // Alpha channel is used only on some 32 bits pixmaps - // and only if render extension is in use. Presently - // we don't have an efficient way to know in advance - // if mask must be applied or not to the image. If an - // alpha channel is set, the function will check if - // the size of the alpha data matches the size of the - // image. In the worst case we'll create an useless - // alpha plane for a pixmap that doesn't need it. - // - - if (alphaState != NULL && alphaState -> data != NULL && - imageState_ -> dstDepth == 32) - { - UnpackAlpha(alphaState, dstData, dstSize, imageByteOrder_); - } - - return 1; -} - -int ServerChannel::handleAuthorization(unsigned char *buffer) -{ - // - // At the present moment we don't support more than - // a single display for each proxy, so authorization - // data is shared among all the channels. - // - // Use the following code to simulate authentication - // failures on a LSB machine: - // - // memcpy(buffer + 12 + (((buffer[6] + 256 * - // buffer[7]) + 3) & ~3), "1234567890123456", 16); - // - - if (auth == NULL) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleAuthorization: Forwarding the real cookie " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - return 0; - } - else if (auth -> checkCookie(buffer) == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleAuthorization: Matched the fake cookie " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - return 1; - } - else - { - #if defined(TEST) || defined(INFO) - *logofs << "handleAuthorization: WARNING! Failed to match " - << "the fake cookie for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - return -1; - } -} - -int ServerChannel::handleAuthorization(const unsigned char *buffer, int size) -{ - // - // Check the X server's response and, in the case of - // an error, print the textual information reported - // by the server. - // - - if (*buffer != 1) - { - const char *reason = NULL; - - // - // At the moment we don't take into account the end- - // ianess of the reply. This should work in any case - // because we simply try to match a few well-known - // error strings. - // - - if (size >= INVALID_COOKIE_SIZE + 8 && - memcmp(buffer + 8, INVALID_COOKIE_DATA, - INVALID_COOKIE_SIZE) == 0) - { - reason = INVALID_COOKIE_DATA; - } - else if (size >= NO_AUTH_PROTO_SIZE + 8 && - memcmp(buffer + 8, NO_AUTH_PROTO_DATA, - NO_AUTH_PROTO_SIZE) == 0) - { - reason = NO_AUTH_PROTO_DATA; - } - else - { - reason = "Unknown"; - } - - #ifdef WARNING - *logofs << "handleAuthorization: WARNING! X connection failed " - << "with error '" << reason << "' on FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - cerr << "Warning" << ": X connection failed " - << "with error '" << reason << "'.\n"; - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "handleAuthorization: X connection successful " - << "on FD#" << fd_ << ".\n" << logofs_flush; - } - #endif - - return 1; -} - -// -// Use a simple encoding. Need to handle the image -// requests in the usual way and the X_ListExtensions -// and X_QueryExtension to hide MIT-SHM and RENDER -// in the reply. -// - -int ServerChannel::handleFastWriteRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - // - // All the NX requests are handled in the - // main message loop. - // - - // - // Since ProtoStep7 (#issue 108) - // - // The X_PutImage can be handled here only - // if a split was not requested. - // - - if ((opcode >= X_NXFirstOpcode && opcode <= X_NXLastOpcode) || - (opcode == X_PutImage && splitState_.resource != nothing) || - opcode == X_ListExtensions || - opcode == X_QueryExtension) - { - return 0; - } - - #ifdef DEBUG - *logofs << "handleFastWriteRequest: Decoding raw request OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - buffer = writeBuffer_.addMessage(4); - - #ifndef __sun - - unsigned int *next = (unsigned int *) decodeBuffer.decodeMemory(4); - - *((unsigned int *) buffer) = *next; - - #else /* #ifndef __sun */ - - memcpy(buffer, decodeBuffer.decodeMemory(4), 4); - - #endif /* #ifndef __sun */ - - size = GetUINT(buffer + 2, bigEndian_) << 2; - - if (size < 4) - { - #ifdef WARNING - *logofs << "handleFastWriteRequest: WARNING! Assuming size 4 " - << "for suspicious message of size " << size - << ".\n" << logofs_flush; - #endif - - size = 4; - } - - writeBuffer_.registerPointer(&buffer); - - if (writeBuffer_.getAvailable() < size - 4 || - (int) size >= control -> TransportFlushBufferSize) - { - #ifdef DEBUG - *logofs << "handleFastWriteRequest: Using scratch buffer for OPCODE#" - << (unsigned int) opcode << " with size " << size << " and " - << writeBuffer_.getLength() << " bytes in buffer.\n" - << logofs_flush; - #endif - - // - // The procedure moving data to shared memory - // assumes that the full message is stored in - // the scratch buffer. We can safely let the - // scratch buffer inherit the decode buffer - // at the next offset. - // - - writeBuffer_.removeMessage(4); - - buffer = writeBuffer_.addScratchMessage(((unsigned char *) - decodeBuffer.decodeMemory(size - 4)) - 4, size); - } - else - { - writeBuffer_.addMessage(size - 4); - - #ifndef __sun - - if (size <= 32) - { - next = (unsigned int *) decodeBuffer.decodeMemory(size - 4); - - for (unsigned int i = 4; i < size; i += sizeof(unsigned int)) - { - *((unsigned int *) (buffer + i)) = *next++; - } - } - else - { - memcpy(buffer + 4, decodeBuffer.decodeMemory(size - 4), size - 4); - } - - #else /* #ifndef __sun */ - - memcpy(buffer + 4, decodeBuffer.decodeMemory(size - 4), size - 4); - - #endif /* #ifndef __sun */ - } - - // - // Opcode could have been tainted by the client - // proxy. Replace the original opcode with the - // one sent in the decode buffer. - // - - *buffer = opcode; - - writeBuffer_.unregisterPointer(); - - if (opcode == X_PutImage) - { - handleImage(opcode, buffer, size); - } - - #if defined(TEST) || defined(OPCODES) - - if (opcode != 0) - { - *logofs << "handleFastWriteRequest: Handled request " - << "OPCODE#" << (unsigned int) opcode << " (" - << DumpOpcode(opcode) << ") for FD#" << fd_ - << " sequence " << clientSequence_ << ". " - << size << " bytes out.\n" << logofs_flush; - } - else - { - *logofs << "handleFastWriteRequest: Handled image or " - << "other request for FD#" << fd_ - << " sequence " << clientSequence_ << ". " - << size << " bytes out.\n" << logofs_flush; - } - - #endif - - handleFlush(flush_if_needed); - - return 1; -} - -// -// Use the simplest encoding except for replies that -// need to be managed some way. -// - -int ServerChannel::handleFastReadReply(EncodeBuffer &encodeBuffer, const unsigned char &opcode, - const unsigned char *&buffer, const unsigned int &size) -{ - // - // If we pushed a X_GetInputFocus in the sequence - // queue this means that the original message was - // a NX request for which we have to provide a NX - // reply. - // - - if ((opcode >= X_NXFirstOpcode && - opcode <= X_NXLastOpcode) || - opcode == X_QueryExtension || - opcode == X_ListExtensions || - opcode == X_GetInputFocus) - { - return 0; - } - - #ifdef DEBUG - *logofs << "handleFastReadReply: Encoding raw reply OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ - << " with size " << size << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeMemory(buffer, size); - - // - // Send back the reply as soon - // as possible. - // - - priority_++; - - int bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) - *logofs << "handleFastReadReply: Handled raw reply OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ << " sequence " - << serverSequence_ << ". " << size << " bytes in, " - << bits << " bits (" << ((float) bits) / 8 - << " bytes) out.\n" << logofs_flush; - #endif - - statistics -> addReplyBits(opcode, size << 3, bits); - - return 1; -} - -int ServerChannel::handleFastReadEvent(EncodeBuffer &encodeBuffer, const unsigned char &opcode, - const unsigned char *&buffer, const unsigned int &size) -{ - #ifdef DEBUG - *logofs << "handleFastReadEvent: Encoding raw " - << (opcode == X_Error ? "error" : "event") << " OPCODE#" - << (unsigned int) opcode << " for FD#" << fd_ - << " with size " << size << ".\n" - << logofs_flush; - #endif - - encodeBuffer.encodeMemory(buffer, size); - - switch (opcode) - { - case X_Error: - case ButtonPress: - case ButtonRelease: - case KeyPress: - case KeyRelease: - { - priority_++; - } - } - - int bits = encodeBuffer.diffBits(); - - #if defined(TEST) || defined(OPCODES) - - if (opcode == X_Error) - { - unsigned char code = *(buffer + 1); - - *logofs << "handleFastReadEvent: Handled error ERR_CODE#" - << (unsigned int) code << " for FD#" << fd_; - - *logofs << " RES_ID#" << GetULONG(buffer + 4, bigEndian_); - - *logofs << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_); - - *logofs << " MAJ_OP#" << (unsigned int) *(buffer + 10); - - *logofs << " sequence " << serverSequence_ << ". " << size - << " bytes in, " << bits << " bits (" << ((float) bits) / 8 - << " bytes) out.\n" << logofs_flush; - } - else - { - *logofs << "handleFastReadEvent: Handled event OPCODE#" - << (unsigned int) *buffer << " for FD#" << fd_ - << " sequence " << serverSequence_ << ". " << size - << " bytes in, " << bits << " bits (" << ((float) bits) / 8 - << " bytes) out.\n" << logofs_flush; - } - - #endif - - statistics -> addEventBits(opcode, size << 3, bits); - - return 1; -} - -void ServerChannel::initCommitQueue() -{ - #ifdef TEST - *logofs << "initCommitQueue: Resetting the queue of split commits " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - for (int i = 0; i < MAX_COMMIT_SEQUENCE_QUEUE; i++) - { - commitSequenceQueue_[i] = 0; - } -} - -void ServerChannel::updateCommitQueue(unsigned short sequence) -{ - for (int i = 0; i < MAX_COMMIT_SEQUENCE_QUEUE - 1; i++) - { - commitSequenceQueue_[i + 1] = commitSequenceQueue_[i]; - } - - #ifdef TEST - *logofs << "updateCommitQueue: Saved " << sequence - << " as last sequence number of image to commit.\n" - << logofs_flush; - #endif - - commitSequenceQueue_[0] = sequence; -} - -int ServerChannel::checkCommitError(unsigned char error, unsigned short sequence, - const unsigned char *buffer) -{ - // - // Check if error is due to an image commit - // generated at the end of a split. - // - // TODO: It should zero the head of the list - // when an event comes with a sequence number - // greater than the value of the last element - // added. - // - - for (int i = 0; i < MAX_COMMIT_SEQUENCE_QUEUE && - commitSequenceQueue_[i] != 0; i++) - { - #ifdef TEST - *logofs << "checkCommitError: Checking committed image's " - << "sequence number " << commitSequenceQueue_[i] - << " with input sequence " << sequence << ".\n" - << logofs_flush; - #endif - - if (commitSequenceQueue_[i] == sequence) - { - #ifdef WARNING - - *logofs << "checkCommitError: WARNING! Failed operation for " - << "FD#" << fd_ << " with ERR_CODE#" - << (unsigned int) *(buffer + 1); - - *logofs << " RES_ID#" << GetULONG(buffer + 4, bigEndian_); - - *logofs << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_); - - *logofs << " MAJ_OP#" << (unsigned int) *(buffer + 10); - - *logofs << " sequence " << sequence << ".\n"; - - *logofs << logofs_flush; - - #endif - - cerr << "Warning" << ": Failed commit operation " - << "with ERR_CODE#" << (unsigned int) error; - - cerr << " RES_ID#" << GetULONG(buffer + 4, bigEndian_); - - cerr << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_); - - cerr << " MAJ_OP#" << (unsigned int) *(buffer + 10); - - cerr << ".\n"; - - #ifdef WARNING - *logofs << "checkCommitError: WARNING! Suppressing error on " - << "OPCODE#" << (unsigned int) opcodeStore_ -> commitSplit - << " for FD#" << fd_ << " with sequence " << sequence - << " at position " << i << ".\n" << logofs_flush; - #endif - - return 0; - } - } - - return 0; -} - -// -// Check if the user pressed the CTRL+ALT+SHIFT+ESC -// keystroke. At the present moment it uses different -// keycodes based on the client OS. This should be -// implemented in a way that is platform independent -// (that's not an easy task, considered that we don't -// have access to the higher level X libraries). -// - -int ServerChannel::checkKeyboardEvent(unsigned char event, unsigned short sequence, - const unsigned char *buffer) -{ - #ifdef TEST - *logofs << "checkKeyboardEvent: Checking escape sequence with byte [1] " - << (void *) ((unsigned) *(buffer + 1)) << " and bytes [28-29] " - << (void *) ((unsigned) GetUINT(buffer + 28, bigEndian_)) - << " for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - #ifdef __APPLE__ - - int alert = (*(buffer + 1) == 0x3d && - GetUINT(buffer + 28, bigEndian_) == 0x2005); - - #else - - int alert = (*(buffer + 1) == 0x09 && - ((GetUINT(buffer + 28, bigEndian_) & - 0x0d) == 0x0d)); - - #endif - - if (alert == 1) - { - #ifdef PANIC - *logofs << "checkKeyboardEvent: PANIC! Received sequence " - << "CTRL+ALT+SHIFT+ESC " << "for FD#"<< fd_ - << ". Showing the abort dialog.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Received sequence CTRL+ALT+SHIFT+ESC. " - << "Showing the abort dialog.\n"; - - HandleAlert(CLOSE_UNRESPONSIVE_X_SERVER_ALERT, 1); - } - - return alert; -} - -// -// Handle the MIT-SHM initialization -// messages exchanged with the remote -// proxy. -// - -int ServerChannel::handleShmemReply(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned int stage, const unsigned char *buffer, - const unsigned int size) -{ - #ifdef TEST - *logofs << "handleShmemReply: Returning shmem reply for " - << "stage " << stage << ".\n" << logofs_flush; - #endif - - if (opcode == X_QueryExtension) - { - encodeBuffer.encodeValue(stage, 2); - -#ifndef ANDROID - shmemState_ -> present = *(buffer + 8); -#else - shmemState_ -> present = 0; - cerr << "Info: handleShmemReply: In android no shared memory. Setting present to 0 hardcoded\n"; -#endif - shmemState_ -> opcode = *(buffer + 9); - shmemState_ -> event = *(buffer + 10); - shmemState_ -> error = *(buffer + 11); - - #ifdef TEST - *logofs << "handleShmemReply: Extension present is " - << shmemState_ -> present << " with base OPCODE#" - << (unsigned int) shmemState_ -> opcode << " base event " - << (unsigned int) shmemState_ -> event << " base error " - << (unsigned int) shmemState_ -> error << ".\n" - << logofs_flush; - #endif - } - else if (opcode == X_GetInputFocus) - { - encodeBuffer.encodeValue(stage, 2); - - encodeBuffer.encodeBoolValue(0); - - if (shmemState_ -> present == 1 && - shmemState_ -> address != NULL && - shmemState_ -> segment > 0 && - shmemState_ -> id > 0) - { - cerr << "Info" << ": Using shared memory parameters 1/" - << (shmemState_ -> size / 1024) << "K.\n"; - -#ifndef ANDROID - shmemState_ -> enabled = 1; -#else - cerr << "Info: handleShmemReply: In android no shared memory. Setting enabled to -1. This should not be displayed\n"; - shmemState_ -> enabled = -1; -#endif - - encodeBuffer.encodeBoolValue(1); - } - else - { - #ifdef TEST - *logofs << "handleShmemReply: WARNING! Not using shared memory " - << "support in X server for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - cerr << "Info" << ": Using shared memory parameters 0/0K.\n"; - - handleShmemStateRemove(); - - encodeBuffer.encodeBoolValue(0); - } - } - else - { - #ifdef PANIC - *logofs << "handleShmemReply: PANIC! Conversation error " - << "handling shared memory support for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Conversation error handling " - << "shared memory support.\n"; - - return -1; - } - - return 1; -} - -int ServerChannel::handleShmemRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - // - // We need to query and initialize MIT-SHM on - // the real X server. To do this we'll need 3 - // requests. At the end we'll have to encode - // the final reply for the X client side. - // - - handleShmemStateAlloc(); - - unsigned int stage; - - decodeBuffer.decodeValue(stage, 2); - - unsigned int expected = shmemState_ -> stage + 1; - - if (stage != expected || stage > 2) - { - #ifdef PANIC - *logofs << "handleShmemRequest: PANIC! Unexpected stage " - << stage << " in handling shared memory " - << "support for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Unexpected stage " - << stage << " in handling shared memory " - << "support for FD#" << fd_ << ".\n"; - - return -1; - } - - switch (stage) - { - case 0: - { - unsigned int enableClient; - unsigned int enableServer; - - decodeBuffer.decodeBoolValue(enableClient); - decodeBuffer.decodeBoolValue(enableServer); - - unsigned int clientSegment; - unsigned int serverSegment; - - decodeBuffer.decodeValue(clientSegment, 29, 9); - decodeBuffer.decodeValue(serverSegment, 29, 9); - - shmemState_ -> segment = serverSegment; - - #ifdef TEST - *logofs << "handleShmemRequest: Size of the shared memory " - << "segment will be " << control -> ShmemServerSize - << ".\n" << logofs_flush; - #endif - - #ifdef TEST - *logofs << "handleShmemRequest: Sending X_QueryExtension request " - << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int) - opcodeStore_ -> getShmemParameters << " in stage " - << stage << ".\n" << logofs_flush; - #endif - - opcode = X_QueryExtension; - - size = 16; - buffer = writeBuffer_.addMessage(size); - - PutUINT(7, buffer + 4, bigEndian_); - - // - // Simply make the query fail if shared - // memory support is disabled by the - // user. - // -#ifndef ANDROID - if (control -> ShmemServer == 1 && - control -> ShmemServerSize > 0 && - enableServer == 1) - { - memcpy(buffer + 8, "MIT-SHM", 7); - } - else - { - memcpy(buffer + 8, "NO-MIT-", 7); - } -#else - cerr << "Info: handleShmemRequest: In android no shared memory. Returning NO-MIT- answer\n"; - - memcpy(buffer + 8, "NO-MIT-", 7); -#endif - sequenceQueue_.push(clientSequence_, opcode, - opcodeStore_ -> getShmemParameters, stage); - - // - // Save the sequence number so we can - // later identify any matching X error - // received from server. - // - - shmemState_ -> sequence = clientSequence_; - - break; - } - case 1: - { - if (shmemState_ -> present == 1) - { - // - // Make the segment read-write for everybody on - // Cygwin (to avoid any lack of support or any - // performance issue) and on MacOS/X (where the - // 0600 mask doesn't seem to work). - // - - #if defined(__CYGWIN32__) || defined(__APPLE__) - - int permissions = 0777; - - #else - - int permissions = 0600; - - #endif - - shmemState_ -> size = control -> ShmemServerSize; - -#ifndef ANDROID - shmemState_ -> id = shmget(IPC_PRIVATE, shmemState_ -> size, - IPC_CREAT | permissions); -#else - cerr << "Info: handleShmemReqyest: In android no shared memory (shmget). This message should not be displayed present should never be 1 in android\n"; - shmemState_ -> id = -1; -#endif - if (shmemState_ -> id >= 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleShmemRequest: Allocated shared memory " - << "segment of " << shmemState_ -> size - << " bytes with id " << shmemState_ -> id - << ".\n" << logofs_flush; - #endif - - -#ifndef ANDROID - shmemState_ -> address = shmat(shmemState_ -> id, 0, 0); -#else - cerr << "Info: handleShmemReqyest: In android no shared memory (shmat). This message should not be displayed. present should never be 1 in android\n"; - shmemState_ -> address = NULL; -#endif - if (shmemState_ -> address != NULL) - { - #ifdef TEST - *logofs << "handleShmemRequest: Sending X_ShmAttach request " - << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int) - opcodeStore_ -> getShmemParameters << " in stage " - << stage << ".\n" << logofs_flush; - #endif - - opcode = shmemState_ -> opcode; - - size = 16; - buffer = writeBuffer_.addMessage(size); - - *(buffer + 1) = X_ShmAttach; - - PutULONG(shmemState_ -> segment, buffer + 4, bigEndian_); - PutULONG(shmemState_ -> id, buffer + 8, bigEndian_); - - *(buffer + 12) = 1; - - shmemState_ -> sequence = clientSequence_; - - break; - } - else - { - #ifdef WARNING - *logofs << "handleShmemRequest: WARNING! Can't attach the shared " - << "memory segment. Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Can't attach the shared memory " - << "segment. Error is " << EGET() << " '" - << ESTR() << "'.\n"; - } - } - else - { - #ifndef __CYGWIN32__ - - #ifdef WARNING - *logofs << "handleShmemRequest: WARNING! Can't create the shared " - << "memory segment. Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Can't create the shared memory " - << "segment. Error is " << EGET() << " '" - << ESTR() << "'.\n"; - - #else - - #ifdef TEST - *logofs << "handleShmemRequest: WARNING! Can't create the shared " - << "memory segment. Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - #endif - } - } - - if (shmemState_ -> present != 0) - { - #ifdef TEST - *logofs << "handleShmemRequest: Resetting shared memory " - << "presence flag for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - shmemState_ -> present = 0; - } - - handleNullRequest(opcode, buffer, size); - - break; - } - default: - { - #ifdef TEST - *logofs << "handleShmemRequest: Sending X_GetInputFocus request " - << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int) - opcodeStore_ -> getShmemParameters << " in stage " - << stage << ".\n" << logofs_flush; - #endif - - opcode = X_GetInputFocus; - - size = 4; - buffer = writeBuffer_.addMessage(size); - - sequenceQueue_.push(clientSequence_, opcode, - opcodeStore_ -> getShmemParameters, stage); - break; - } - } - - shmemState_ -> stage += 1; - - return 1; -} - -// -// Handling of MIT-SHM extension has been plugged late in -// the design, so we have to make some assumptions. Image -// is a X_PutImage request contained either in the scratch -// buffer or in the normal write buffer. We need to move -// the image data to the shared memory segment and replace -// the X_PutImage request with a X_ShmPutImage. -// - -int ServerChannel::handleShmem(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size) -{ - if (shmemState_ == NULL || shmemState_ -> enabled != 1) - { - #ifdef TEST - - if (shmemState_ != NULL) - { - *logofs << "handleShmem: PANIC! Shared memory " - << "state found but support is not enabled " - << "for FD#" << fd_ << " in stage " - << shmemState_ -> stage << ".\n" - << logofs_flush; - } - - #endif - - return 0; - } -#ifdef ANDROID - cerr << "Info: handleShmem: In android no shared memory. enabled should never be 1. This should not be displayed\n"; - return 0; -#endif - - // - // Ignore null requests and requests that will not result - // in a single X_PutImage. To conform with the other func- - // tions, we get the opcode passed as a parameter. It can - // be zero if we don't want the write loop to put opcode - // and length in the resulting buffer. Anyway we are only - // interested in the original opcode of the request, that - // is stored in the image state. - // - - unsigned char *dstData = buffer + 24; - unsigned int dstDataSize = size - 24; - - if (dstDataSize == 0 || dstDataSize > - (unsigned int) control -> MaximumRequestSize) - { - #ifdef TEST - *logofs << "handleShmem: Ignoring image with opcode " - << (unsigned int) imageState_ -> opcode - << " and size " << size << " for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - return 0; - } - - #ifdef TEST - *logofs << "handleShmem: Handling image with opcode " - << (unsigned int) imageState_ -> opcode - << " and size " << size << " for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - // - // Get image data from buffer. - // - - if (imageState_ -> opcode == X_PutImage) - { - // - // We still need to get the image's data. - // - - imageState_ -> format = *(buffer + 1); - - imageState_ -> drawable = GetULONG(buffer + 4, bigEndian_); - imageState_ -> gcontext = GetULONG(buffer + 8, bigEndian_); - - imageState_ -> dstWidth = GetUINT(buffer + 12, bigEndian_); - imageState_ -> dstHeight = GetUINT(buffer + 14, bigEndian_); - - imageState_ -> srcX = 0; - imageState_ -> srcY = 0; - - imageState_ -> srcWidth = imageState_ -> dstWidth; - imageState_ -> srcHeight = imageState_ -> dstHeight; - - imageState_ -> dstX = GetUINT(buffer + 16, bigEndian_); - imageState_ -> dstY = GetUINT(buffer + 18, bigEndian_); - - imageState_ -> leftPad = *(buffer + 20); - imageState_ -> dstDepth = *(buffer + 21); - - imageState_ -> dstLines = imageState_ -> dstHeight; - - imageState_ -> dstLength = size - 24; - } - - // - // Skip the MIT-SHM operation if the image - // is 1 bits-per-plane. - // - - if (imageState_ -> dstDepth == 1) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleShmem: Ignoring image with opcode " - << (unsigned int) imageState_ -> opcode << " depth " - << (unsigned int) imageState_ -> dstDepth << " and " - << "size " << size << " for FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - return 0; - } - - // - // If the image can't fit in the available - // space, check if the completion event is - // arrived. - // - - #if defined(TEST) || defined(INFO) - - if (isTimestamp(shmemState_ -> last) == 0 && - shmemState_ -> offset != 0) - { - *logofs << "handleShmem: PANIC! No timestamp for sequence " - << shmemState_ -> sequence << " with offset " - << shmemState_ -> offset << ".\n" - << logofs_flush; - } - - #endif - - if (shmemState_ -> offset + imageState_ -> dstLength > - shmemState_ -> size) - { - if (imageState_ -> dstLength > shmemState_ -> size) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleShmem: WARNING! Can't fit the image " - << "in the available memory segment for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - return 0; - } - else if (handleShmemEvent() <= 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleShmem: WARNING! Missing completion " - << "after " << diffTimestamp(shmemState_ -> last, - getTimestamp()) << " Ms for shared memory " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - return 0; - } - } - - // - // Let image start at current offset - // in the shared segment. - // - - #ifdef TEST - *logofs << "handleShmem: Copying " << dstDataSize - << " bytes to shared memory at offset " - << shmemState_ -> offset << " for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - memcpy((unsigned char *) shmemState_ -> address + - shmemState_ -> offset, dstData, dstDataSize); - - // - // Get rid of the original X_PutImage - // request. - // - - if (writeBuffer_.getScratchData() != NULL) - { - writeBuffer_.removeScratchMessage(); - } - else - { - writeBuffer_.removeMessage(size); - } - - // - // Add a X_ShmPutImage request to the - // write buffer. - // - - buffer = writeBuffer_.addMessage(40); - - *buffer = shmemState_ -> opcode; - - *(buffer + 1) = X_ShmPutImage; - - PutUINT(40 >> 2, buffer + 2, bigEndian_); - - PutULONG(imageState_ -> drawable, buffer + 4, bigEndian_); - PutULONG(imageState_ -> gcontext, buffer + 8, bigEndian_); - - PutUINT(imageState_ -> dstWidth, buffer + 12, bigEndian_); - PutUINT(imageState_ -> dstLines, buffer + 14, bigEndian_); - - PutUINT(imageState_ -> srcX, buffer + 16, bigEndian_); - PutUINT(imageState_ -> srcY, buffer + 18, bigEndian_); - - PutUINT(imageState_ -> dstWidth, buffer + 20, bigEndian_); - PutUINT(imageState_ -> dstLines, buffer + 22, bigEndian_); - - PutUINT(imageState_ -> dstX, buffer + 24, bigEndian_); - PutUINT(imageState_ -> dstY, buffer + 26, bigEndian_); - - *(buffer + 28) = imageState_ -> dstDepth; - *(buffer + 29) = imageState_ -> format; - *(buffer + 30) = 1; - - PutULONG(shmemState_ -> segment, buffer + 32, bigEndian_); - PutULONG(shmemState_ -> offset, buffer + 36, bigEndian_); - - shmemState_ -> offset += dstDataSize; - - shmemState_ -> sequence = clientSequence_; - shmemState_ -> last = getTimestamp(); - - #ifdef TEST - *logofs << "handleShmem: Saved shared memory sequence " - << shmemState_ -> sequence << " for FD#" << fd_ - << " with offset " << shmemState_ -> offset - << " at " << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - - // - // Make the X server read immediately - // from the shared memory buffer and - // produce the completion event. - // - - handleFlush(flush_if_any); - - return 1; -} - -// -// Try to read more events from the socket in the -// attempt to get the completion event required -// to reset the MIT-SHM segment. -// - -int ServerChannel::handleShmemEvent() -{ - #if defined(TEST) || defined(INFO) - *logofs << "handleShmemEvent: Waiting for shared memory " - << "sequence " << shmemState_ -> sequence - << " for X server FD#" << fd_ << ".\n" - << logofs_flush; - - T_timestamp startTs = getTimestamp(); - - #endif - - while (isTimestamp(shmemState_ -> last) != 0) - { - if (handleWait(control -> ShmemTimeout) <= 0) - { - break; - } - #if defined(TEST) || defined(INFO) - else - { - *logofs << "handleShmemEvent: WARNING! Encoded events " - << "for FD#" << fd_ << " at " << strMsTimestamp() - << ".\n" << logofs_flush; - } - #endif - } - - if (isTimestamp(shmemState_ -> last) == 0) - { - #if defined(TEST) || defined(INFO) - *logofs << "handleShmemEvent: Spent " - << diffTimestamp(startTs, getTimestamp()) << " Ms " - << "waiting for shared memory sequence for FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - return 1; - } - - #if defined(TEST) || defined(INFO) - *logofs << "handleShmemEvent: WARNING! Can't reset shared " - << "memory sequence for FD#" << fd_ << " after " - << diffTimestamp(shmemState_ -> last, getTimestamp()) - << " Ms.\n" << logofs_flush; - #endif - - return 0; -} - -int ServerChannel::checkShmemEvent(unsigned char event, unsigned short sequence, - const unsigned char *buffer) -{ - if (isTimestamp(shmemState_ -> last) == 1 && - sequence == shmemState_ -> sequence) - { - #ifdef TEST - *logofs << "checkShmemEvent: Reset shared memory sequence " - << shmemState_ -> sequence << " for FD#" << fd_ - << " after " << diffTimestamp(shmemState_ -> last, - getTimestamp()) << " Ms.\n" << logofs_flush; - #endif - - shmemState_ -> sequence = 0; - shmemState_ -> offset = 0; - shmemState_ -> last = nullTimestamp(); - } - #ifdef TEST - else - { - *logofs << "checkShmemEvent: Skipping past shared memory " - << "image sequence " << sequence << " for FD#" - << fd_ << ".\n" << logofs_flush; - } - #endif - - return 1; -} - -int ServerChannel::checkShmemError(unsigned char error, unsigned short sequence, - const unsigned char *buffer) -{ - #ifdef TEST - - *logofs << "checkShmemError: WARNING! Failed operation for " - << "FD#" << fd_ << " in stage " << shmemState_ -> stage - << " with ERR_CODE#" << (unsigned int) *(buffer + 1); - - *logofs << " RES_ID#" << GetULONG(buffer + 4, bigEndian_); - - *logofs << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_); - - *logofs << " MAJ_OP#" << (unsigned int) *(buffer + 10); - - *logofs << " sequence " << sequence << ".\n"; - - *logofs << logofs_flush; - - #endif - - // - // If enabled flag is <= 0 we are still - // in the inizialization phase. In this - // case force presence to false. - // - - if (shmemState_ -> enabled != 1) - { - if (shmemState_ -> present != 0) - { - #ifdef TEST - *logofs << "checkShmemError: Resetting shared memory " - << "presence flag for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - shmemState_ -> present = 0; - } - - return 0; - } - - if (shmemState_ -> sequence == sequence) - { - // - // Reset the sequence and timestamp. - // - - shmemState_ -> sequence = 0; - shmemState_ -> offset = 0; - shmemState_ -> last = nullTimestamp(); - } - - return 1; -} - -int ServerChannel::handleFontRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - // - // Send a synchronization request and use - // the reply to return the requested font - // path. - // - - #ifdef TEST - *logofs << "handleFontRequest: Sending X_GetInputFocus request " - << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int) - opcodeStore_ -> getFontParameters << ".\n" - << logofs_flush; - #endif - - opcode = X_GetInputFocus; - - size = 4; - buffer = writeBuffer_.addMessage(size); - - sequenceQueue_.push(clientSequence_, X_GetInputFocus, - opcodeStore_ -> getFontParameters); - - return 1; -} - -int ServerChannel::handleFontReply(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) -{ - #ifdef TEST - *logofs << "handleFontReply: Encoding font operation " - << "reply with size " << size << ".\n" - << logofs_flush; - #endif - - char data[256]; - - if (fontPort_ != -1) - { - sprintf(data + 1, "tcp/localhost:%d", fontPort_); - } - else - { - *(data + 1) = '\0'; - } - - *data = strlen(data + 1); - - unsigned char *next = (unsigned char *) data; - - unsigned int length = (unsigned int) (*next++); - - encodeBuffer.encodeValue(length, 8); - - encodeBuffer.encodeTextData(next, length); - - return 1; -} - -int ServerChannel::handleCacheRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - unsigned int mask; - - decodeBuffer.decodeCachedValue(mask, 32, clientCache_ -> - setCacheParametersCache); - - splitState_.save = (mask >> 8) & 0xff; - splitState_.load = mask & 0xff; - - #ifdef TEST - *logofs << "handleCacheRequest: Set cache parameters to " - << "save " << splitState_.save << " load " - << splitState_.load << ".\n" << logofs_flush; - #endif - - handleNullRequest(opcode, buffer, size); - - return 1; -} - -int ServerChannel::handleStartSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - // - // Prepare for the split for the selected - // resource. Old proxy versions only used - // the split store at position 0. - // - - // Since ProtoStep7 (#issue 108) - unsigned char resource; - - decodeBuffer.decodeCachedValue(resource, 8, - clientCache_ -> resourceCache); - - splitState_.resource = resource; - - splitState_.current = splitState_.resource; - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleStartSplitRequest: SPLIT! Registered id " - << splitState_.resource << " as resource " - << "waiting for a split.\n" << logofs_flush; - #endif - - handleNullRequest(opcode, buffer, size); - - return 1; -} - -int ServerChannel::handleEndSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size) -{ - // - // Verify that the agent resource matches. - // - - // Since ProtoStep7 (#issue 108) - unsigned char resource; - - decodeBuffer.decodeCachedValue(resource, 8, - clientCache_ -> resourceCache); - - #ifdef TEST - - if (splitState_.resource == nothing) - { - #ifdef PANIC - *logofs << "handleEndSplitRequest: PANIC! SPLIT! Received an end of " - << "split for resource id " << (unsigned int) *(buffer + 1) - << " without a previous start.\n" - << logofs_flush; - #endif - - HandleCleanup(); - } - else if (resource != splitState_.resource) - { - #ifdef PANIC - *logofs << "handleEndSplitRequest: PANIC! SPLIT! Invalid resource id " - << resource << " received while waiting for resource id " - << splitState_.resource << ".\n" << logofs_flush; - #endif - - HandleCleanup(); - } - - #endif - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleEndSplitRequest: SPLIT! Reset id " - << splitState_.resource << " as resource " - << "selected for splits.\n" << logofs_flush; - #endif - - splitState_.resource = nothing; - - handleNullRequest(opcode, buffer, size); - - return 1; -} - -int ServerChannel::handleSplitChecksum(DecodeBuffer &decodeBuffer, T_checksum &checksum) -{ - unsigned int receive; - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeBoolValue(receive); - - if (receive == 1) - { - checksum = new md5_byte_t[MD5_LENGTH]; - - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - decodeBuffer.decodeValue(receive, 8); - - if (checksum != NULL) - { - checksum[i] = (unsigned char) receive; - } - } - - #if defined(TEST) || defined(SPLIT) - *logofs << "handleSplitChecksum: SPLIT! Received checksum " - << "[" << DumpChecksum(checksum) << "].\n" - << logofs_flush; - #endif - - return 1; - } - - return 0; -} - -void ServerChannel::handleShmemStateAlloc() -{ - if (shmemState_ == NULL) - { - shmemState_ = new T_shmem_state(); - - shmemState_ -> stage = -1; - shmemState_ -> present = -1; - shmemState_ -> enabled = -1; - - shmemState_ -> segment = -1; - shmemState_ -> id = -1; - shmemState_ -> address = NULL; - shmemState_ -> size = 0; - - shmemState_ -> opcode = 0xff; - shmemState_ -> event = 0xff; - shmemState_ -> error = 0xff; - - shmemState_ -> sequence = 0; - shmemState_ -> offset = 0; - shmemState_ -> last = nullTimestamp(); - - shmemState_ -> checked = 0; - } -} - -void ServerChannel::handleShmemStateRemove() -{ - if (shmemState_ != NULL) - { - if (shmemState_ -> address != NULL) - { -#ifndef ANDROID - shmdt((char *) shmemState_ -> address); -#else - cerr << "Info: handleShmemStateRemove: In android no shared memory. This should not be displayed. address should always be NULL\n"; -#endif - } - - if (shmemState_ -> id > 0) - { -#ifndef ANDROID - shmctl(shmemState_ -> id, IPC_RMID, 0); -#else - cerr << "Info: handleShmemStateRemove: In android no shared memory. This should not be displayed. id should always be 0\n"; -#endif - } - - delete shmemState_; - - shmemState_ = NULL; - } -} - -void ServerChannel::handleUnpackStateInit(int resource) -{ - if (unpackState_[resource] == NULL) - { - unpackState_[resource] = new T_unpack_state(); - - if (unpackState_[resource] == NULL) - { - #ifdef PANIC - *logofs << "handleUnpackStateInit: PANIC! Can't allocate " - << "memory for unpack state in context [A].\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory for " - << "unpack state in context [A].\n"; - - HandleAbort(); - } - - unpackState_[resource] -> geometry = NULL; - unpackState_[resource] -> colormap = NULL; - unpackState_[resource] -> alpha = NULL; - } -} - -void ServerChannel::handleUnpackAllocGeometry(int resource) -{ - if (unpackState_[resource] -> geometry == NULL) - { - unpackState_[resource] -> geometry = new T_geometry(); - - if (unpackState_[resource] -> geometry == NULL) - { - #ifdef PANIC - *logofs << "handleUnpackAllocGeometry: PANIC! Can't allocate " - << "memory for unpack state in context [B].\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory for " - << "unpack state in context [B].\n"; - - HandleAbort(); - } - - unpackState_[resource] -> geometry -> depth1_bpp = 4; - unpackState_[resource] -> geometry -> depth4_bpp = 4; - unpackState_[resource] -> geometry -> depth8_bpp = 8; - unpackState_[resource] -> geometry -> depth16_bpp = 16; - unpackState_[resource] -> geometry -> depth24_bpp = 32; - unpackState_[resource] -> geometry -> depth32_bpp = 32; - - unpackState_[resource] -> geometry -> red_mask = 0xff0000; - unpackState_[resource] -> geometry -> green_mask = 0x00ff00; - unpackState_[resource] -> geometry -> blue_mask = 0x0000ff; - - unpackState_[resource] -> geometry -> image_byte_order = imageByteOrder_; - unpackState_[resource] -> geometry -> bitmap_bit_order = bitmapBitOrder_; - unpackState_[resource] -> geometry -> scanline_unit = scanlineUnit_; - unpackState_[resource] -> geometry -> scanline_pad = scanlinePad_; - } -} - -void ServerChannel::handleUnpackAllocColormap(int resource) -{ - if (unpackState_[resource] -> colormap == NULL) - { - unpackState_[resource] -> colormap = new T_colormap(); - - if (unpackState_[resource] -> colormap == NULL) - { - #ifdef PANIC - *logofs << "handleUnpackAllocColormap: PANIC! Can't allocate " - << "memory for unpack state in context [C].\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory for " - << "unpack state in context [C].\n"; - - HandleAbort(); - } - - unpackState_[resource] -> colormap -> entries = 0; - unpackState_[resource] -> colormap -> data = NULL; - } -} - -void ServerChannel::handleUnpackAllocAlpha(int resource) -{ - if (unpackState_[resource] -> alpha == NULL) - { - unpackState_[resource] -> alpha = new T_alpha(); - - if (unpackState_[resource] -> alpha == NULL) - { - #ifdef PANIC - *logofs << "handleUnpackAllocAlpha: PANIC! Can't allocate " - << "memory for unpack state in context [D].\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory for " - << "unpack state in context [D].\n"; - - HandleAbort(); - } - - unpackState_[resource] -> alpha -> entries = 0; - unpackState_[resource] -> alpha -> data = NULL; - } -} - -void ServerChannel::handleUnpackStateRemove(int resource) -{ - if (unpackState_[resource] != NULL) - { - delete unpackState_[resource] -> geometry; - - if (unpackState_[resource] -> colormap != NULL) - { - delete [] unpackState_[resource] -> colormap -> data; - } - - delete unpackState_[resource] -> colormap; - - if (unpackState_[resource] -> alpha != NULL) - { - delete [] unpackState_[resource] -> alpha -> data; - } - - delete unpackState_[resource] -> alpha; - - delete unpackState_[resource]; - - unpackState_[resource] = NULL; - } -} - -void ServerChannel::handleEncodeCharInfo(const unsigned char *nextSrc, EncodeBuffer &encodeBuffer) -{ - unsigned int value = GetUINT(nextSrc, bigEndian_) | - (GetUINT(nextSrc + 10, bigEndian_) << 16); - - encodeBuffer.encodeCachedValue(value, 32, - *serverCache_ -> queryFontCharInfoCache[0], 6); - - nextSrc += 2; - - for (unsigned int i = 1; i < 5; i++) - { - unsigned int value = GetUINT(nextSrc, bigEndian_); - - nextSrc += 2; - - encodeBuffer.encodeCachedValue(value, 16, - *serverCache_ -> queryFontCharInfoCache[i], 6); - } -} - -int ServerChannel::setBigEndian(int flag) -{ - bigEndian_ = flag; - - readBuffer_.setBigEndian(flag); - - return 1; -} - -int ServerChannel::setReferences() -{ - #ifdef TEST - *logofs << "ServerChannel: Initializing the static " - << "members for the server channels.\n" - << logofs_flush; - #endif - - #ifdef REFERENCES - - references_ = 0; - - #endif - - return 1; -} diff --git a/nxcomp/ServerChannel.h b/nxcomp/ServerChannel.h deleted file mode 100644 index 374e52896..000000000 --- a/nxcomp/ServerChannel.h +++ /dev/null @@ -1,529 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ServerChannel_H -#define ServerChannel_H - -#include "List.h" -#include "Channel.h" - -#include "SequenceQueue.h" - -#include "ServerReadBuffer.h" - -#include "Unpack.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// How many sequence numbers of split commit -// requests we are going to save in order to -// mask errors. -// - -#define MAX_COMMIT_SEQUENCE_QUEUE 16 - -// -// Define this to know when a channel -// is created or destroyed. -// - -#undef REFERENCES - -// -// This class implements the X server -// side compression of X protocol. -// - -class ServerChannel : public Channel -{ - public: - - ServerChannel(Transport *transport, StaticCompressor *compressor); - - virtual ~ServerChannel(); - - virtual int handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, - unsigned int length); - - virtual int handleWrite(const unsigned char *message, unsigned int length); - - virtual int handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, - T_store_action action, int position, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size) - { - return 0; - } - - virtual int handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, - T_store_action action, int position, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - virtual int handleSplit(EncodeBuffer &encodeBuffer) - { - return 0; - } - - virtual int handleSplit(DecodeBuffer &decodeBuffer); - - virtual int handleSplitEvent(EncodeBuffer &encodeBuffer, Split *split); - - virtual int handleSplitEvent(DecodeBuffer &decodeBuffer) - { - return 0; - } - - // - // Send the last motion notify event - // received from the X server to the - // remote proxy. - // - - virtual int handleMotion(EncodeBuffer &encodeBuffer); - - virtual int handleCompletion(EncodeBuffer &encodeBuffer) - { - return 0; - } - - virtual int handleConfiguration(); - - virtual int handleFinish(); - - virtual int handleAsyncEvents(); - - virtual int needSplit() const - { - return 0; - } - - virtual int needMotion() const - { - return (lastMotion_[0] != '\0'); - } - - virtual T_channel_type getType() const - { - return channel_x11; - } - - int setBigEndian(int flag); - - // - // Initialize the static members. - // - - static int setReferences(); - - private: - - int handleFastReadReply(EncodeBuffer &encodeBuffer, const unsigned char &opcode, - const unsigned char *&buffer, const unsigned int &size); - - int handleFastReadEvent(EncodeBuffer &encodeBuffer, const unsigned char &opcode, - const unsigned char *&buffer, const unsigned int &size); - - int handleFastWriteRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - // - // Handle the fake authorization cookie - // and the X server's reply. - // - - int handleAuthorization(unsigned char *buffer); - int handleAuthorization(const unsigned char *buffer, int size); - - // - // Set the unpack colormap and the alpha - // blending data to be used to unpack - // images. - // - - int handleGeometry(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size); - - int handleColormap(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size); - - int handleAlpha(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size); - - // - // Manage the decoded buffer to unpack - // the image and move the data to the - // shared memory segment. - // - - int handleImage(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size); - - // - // Uncompress a packed image in one - // or more graphic X requests. - // - - int handleUnpack(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size); - - // - // Move the image to the shared - // memory buffer. - // - - int handleShmem(unsigned char &opcode, unsigned char *&buffer, - unsigned int &size); - - // - // Handle suppression of error on - // commit of image splits. - // - - void initCommitQueue(); - - void updateCommitQueue(unsigned short sequence); - - int checkCommitError(unsigned char error, unsigned short sequence, - const unsigned char *buffer); - - void clearCommitQueue() - { - if (commitSequenceQueue_[0] != 0) - { - initCommitQueue(); - } - } - - // - // Check if the user pressed the - // CTRL+ALT+SHIFT+ESC keystroke. - // - - int checkKeyboardEvent(unsigned char event, unsigned short sequence, - const unsigned char *buffer); - - // - // Other utilities. - // - - void handleEncodeCharInfo(const unsigned char *nextSrc, EncodeBuffer &encodeBuffer); - - // - // Handle the MIT-SHM initialization - // messages exchanged with the remote - // proxy. - // - - int handleShmemRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - - int handleShmemReply(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned int stage, const unsigned char *buffer, - const unsigned int size); - - // - // Try to read more events in the attempt to - // get the MIT-SHM image completion event - // from the X server. - // - - int handleShmemEvent(); - - // - // Handle the MIT-SHM events as they are read - // from the socket. - // - - int checkShmemEvent(unsigned char event, unsigned short sequence, - const unsigned char *buffer); - - int checkShmemError(unsigned char error, unsigned short sequence, - const unsigned char *buffer); - - // - // Query the port used to tunnel - // the font server connections. - // - - int handleFontRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - int handleFontReply(EncodeBuffer &encodeBuffer, const unsigned char opcode, - const unsigned char *buffer, const unsigned int size); - - // - // Set the cache policy for image - // requests. - // - - int handleCacheRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - // - // Decode the start and end split - // requests. - // - - int handleStartSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - int handleEndSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - // - // Remove the split store and the - // incomplete messages from the - // memory cache. - // - - int handleAbortSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - // - // Send the split requests to the - // X server once they have been - // recomposed. - // - - int handleCommitSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, - unsigned char *&buffer, unsigned int &size); - - int handleSplitChecksum(DecodeBuffer &decodeBuffer, T_checksum &checksum); - - // - // Allocate and free the shared memory - // support resources. - // - - void handleShmemStateAlloc(); - void handleShmemStateRemove(); - - // - // Temporary storage for the image info. - // - - void handleImageStateAlloc(unsigned char opcode) - { - if (imageState_ == NULL) - { - imageState_ = new T_image_state(); - } - - imageState_ -> opcode = opcode; - } - - void handleImageStateRemove() - { - if (imageState_ != NULL) - { - delete imageState_; - - imageState_ = NULL; - } - } - - // - // Store the information needed to unpack - // images per each known agent's client. - // - - void handleUnpackStateInit(int resource); - - void handleUnpackAllocGeometry(int resource); - void handleUnpackAllocColormap(int resource); - void handleUnpackAllocAlpha(int resource); - - void handleUnpackStateRemove(int resource); - - typedef struct - { - T_geometry *geometry; - T_colormap *colormap; - T_alpha *alpha; - - } T_unpack_state; - - T_unpack_state *unpackState_[256]; - - // - // Own read buffer. It is able to identify - // full messages read from X descriptor. - // - - ServerReadBuffer readBuffer_; - - // - // Sequence number of last request coming - // from X client or X server. - // - - unsigned int clientSequence_; - unsigned int serverSequence_; - - // - // Used to identify replies based on sequence - // number of original request. - // - - SequenceQueue sequenceQueue_; - - // - // Last motion notify read from the X server. - // - - unsigned char lastMotion_[32]; - - // - // Sequence numbers of last auto-generated - // put image requests. Needed to intercept - // and suppress errors generated by such - // requests. - // - - unsigned int commitSequenceQueue_[MAX_COMMIT_SEQUENCE_QUEUE]; - - // - // Let agent select which expose - // events is going to receive. - // - - unsigned int enableExpose_; - unsigned int enableGraphicsExpose_; - unsigned int enableNoExpose_; - - // - // Used in initialization and handling - // of MIT-SHM shared memory put images. - // - - typedef struct - { - int stage; - int present; - int enabled; - int segment; - int id; - void *address; - unsigned int size; - - unsigned char opcode; - unsigned char event; - unsigned char error; - - unsigned int sequence; - unsigned int offset; - T_timestamp last; - - unsigned int checked; - - } T_shmem_state; - - T_shmem_state *shmemState_; - - // - // Used to pass current image data between - // the different decompression stages. - // - - typedef struct - { - unsigned char opcode; - - unsigned int drawable; - unsigned int gcontext; - - unsigned char method; - - unsigned char format; - unsigned char srcDepth; - unsigned char dstDepth; - - unsigned int srcLength; - unsigned int dstLength; - unsigned int dstLines; - - short int srcX; - short int srcY; - unsigned short srcWidth; - unsigned short srcHeight; - - short int dstX; - short int dstY; - unsigned short dstWidth; - unsigned short dstHeight; - - unsigned char leftPad; - - } T_image_state; - - T_image_state *imageState_; - - // - // The flags is set according to the - // split load and save policy set by - // the encoding side. - // - - typedef struct - { - int resource; - int current; - int load; - int save; - int commit; - - } T_split_state; - - T_split_state splitState_; - - // - // List of agent resources. - // - - List splitResources_; - - // - // Keep track of object creation and - // deletion. - // - - private: - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -#endif /* ServerChannel_H */ diff --git a/nxcomp/ServerProxy.cpp b/nxcomp/ServerProxy.cpp deleted file mode 100644 index 5d1765183..000000000 --- a/nxcomp/ServerProxy.cpp +++ /dev/null @@ -1,617 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include - -#include "NXalert.h" - -#include "Socket.h" - -#include "ServerProxy.h" - -#include "ServerChannel.h" -#include "GenericChannel.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Log the operations related to sending -// and receiving the control tokens. -// - -#undef TOKEN - -ServerProxy::ServerProxy(int proxyFd) : Proxy(proxyFd) - -{ - xServerAddrFamily_ = -1; - xServerAddrLength_ = 0; - - xServerAddr_ = NULL; - xServerDisplay_ = NULL; - - cupsServerPort_ = NULL; - smbServerPort_ = NULL; - mediaServerPort_ = NULL; - httpServerPort_ = NULL; - - fontServerPort_ = NULL; - - #ifdef DEBUG - *logofs << "ServerProxy: Created new object at " << this - << ".\n" << logofs_flush; - #endif -} - -ServerProxy::~ServerProxy() -{ - delete xServerAddr_; - - delete [] xServerDisplay_; - - delete [] fontServerPort_; - - #ifdef DEBUG - *logofs << "ServerProxy: Deleted object at " << this - << ".\n" << logofs_flush; - #endif -} - -void ServerProxy::handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, - sockaddr *xServerAddr, unsigned int xServerAddrLength) -{ - delete xServerAddr_; - - xServerAddr_ = xServerAddr; - - xServerAddrFamily_ = xServerAddrFamily; - xServerAddrLength_ = xServerAddrLength; - - delete [] xServerDisplay_; - - xServerDisplay_ = new char[strlen(xServerDisplay) + 1]; - - strcpy(xServerDisplay_, xServerDisplay); - - #ifdef DEBUG - *logofs << "ServerProxy: Set display configuration to display '" - << xServerDisplay_ << "'.\n" - << logofs_flush; - #endif -} - -void ServerProxy::handlePortConfiguration(ChannelEndPoint &cupsServerPort, - ChannelEndPoint &smbServerPort, - ChannelEndPoint &mediaServerPort, - ChannelEndPoint &httpServerPort, - const char *fontServerPort) -{ - cupsServerPort_ = cupsServerPort; - smbServerPort_ = smbServerPort; - mediaServerPort_ = mediaServerPort; - httpServerPort_ = httpServerPort; - - delete [] fontServerPort_; - - fontServerPort_ = new char[strlen(fontServerPort) + 1]; - - strcpy(fontServerPort_, fontServerPort); - - #ifdef DEBUG - *logofs << "ServerProxy: Set port configuration to CUPS " - << cupsServerPort_ << ", SMB " << smbServerPort_ - << ", media " << mediaServerPort_ << ", HTTP " - << httpServerPort_ << ".\n" - << logofs_flush; - #endif -} - -int ServerProxy::handleNewConnection(T_channel_type type, int clientFd) -{ - switch (type) - { - case channel_font: - { - return handleNewGenericConnection(clientFd, channel_font, "font"); - } - case channel_slave: - { - return handleNewSlaveConnection(clientFd); - } - default: - { - #ifdef PANIC - *logofs << "ServerProxy: PANIC! Unsupported channel with type '" - << getTypeName(type) << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unsupported channel with type '" - << getTypeName(type) << "'.\n"; - - return -1; - } - } -} - -int ServerProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId) -{ - switch (type) - { - case channel_x11: - { - return handleNewXConnectionFromProxy(channelId); - } - case channel_cups: - { - return handleNewGenericConnectionFromProxy(channelId, channel_cups, - cupsServerPort_, "CUPS"); - } - case channel_smb: - { - smbServerPort_.setDefaultTCPInterface(1); - return handleNewGenericConnectionFromProxy(channelId, channel_smb, - smbServerPort_, "SMB"); - } - case channel_media: - { - return handleNewGenericConnectionFromProxy(channelId, channel_media, - mediaServerPort_, "media"); - } - case channel_http: - { - return handleNewGenericConnectionFromProxy(channelId, channel_http, - httpServerPort_, "HTTP"); - } - case channel_slave: - { - return handleNewSlaveConnectionFromProxy(channelId); - } - default: - { - #ifdef PANIC - *logofs << "ServerProxy: PANIC! Unsupported channel with type '" - << getTypeName(type) << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Unsupported channel with type '" - << getTypeName(type) << "'.\n"; - - return -1; - } - } -} - -int ServerProxy::handleNewAgentConnection(Agent *agent) -{ - #ifdef PANIC - *logofs << "ServerProxy: PANIC! Can't create an agent " - << "connection at this side.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create an agent " - << "connection at this side.\n"; - - return -1; -} - -int ServerProxy::handleNewXConnection(int clientFd) -{ - #ifdef PANIC - *logofs << "ServerProxy: PANIC! Can't create a new X channel " - << "with FD#" << clientFd << " at this side.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't create a new X channel " - << "with FD#" << clientFd << " at this side.\n"; - - return -1; -} - -int ServerProxy::handleNewXConnectionFromProxy(int channelId) -{ - // - // Connect to the real X server. - // - - int retryConnect = control -> OptionServerRetryConnect; - - int xServerFd; - - for (;;) - { - xServerFd = socket(xServerAddrFamily_, SOCK_STREAM, PF_UNSPEC); - - if (xServerFd < 0) - { - #ifdef PANIC - *logofs << "ServerProxy: PANIC! Call to socket failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Call to socket failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - return -1; - } - - #ifdef TEST - *logofs << "ServerProxy: Trying to connect to X server '" - << xServerDisplay_ << "'.\n" << logofs_flush; - #endif - - int result = connect(xServerFd, xServerAddr_, xServerAddrLength_); - - getNewTimestamp(); - - if (result < 0) - { - #ifdef WARNING - *logofs << "ServerProxy: WARNING! Connection to '" - << xServerDisplay_ << "' failed with error '" - << ESTR() << "'. Retrying.\n" << logofs_flush; - #endif - - close(xServerFd); - - if (--retryConnect == 0) - { - #ifdef PANIC - *logofs << "ServerProxy: PANIC! Connection to '" - << xServerDisplay_ << "' for channel ID#" - << channelId << " failed. Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Connection to '" - << xServerDisplay_ << "' failed. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - close(xServerFd); - - return -1; - } - - if (activeChannels_.getSize() == 0) - { - sleep(2); - } - else - { - sleep(1); - } - } - else - { - break; - } - } - - assignChannelMap(channelId, xServerFd); - - #ifdef TEST - *logofs << "ServerProxy: X server descriptor FD#" << xServerFd - << " mapped to channel ID#" << channelId << ".\n" - << logofs_flush; - #endif - - // - // Turn queuing off for path proxy-to-X-server. - // - - if (control -> OptionServerNoDelay == 1) - { - SetNoDelay(xServerFd, control -> OptionServerNoDelay); - } - - // - // If requested, set the size of the TCP send - // and receive buffers. - // - - if (control -> OptionServerSendBuffer != -1) - { - SetSendBuffer(xServerFd, control -> OptionServerSendBuffer); - } - - if (control -> OptionServerReceiveBuffer != -1) - { - SetReceiveBuffer(xServerFd, control -> OptionServerReceiveBuffer); - } - - if (allocateTransport(xServerFd, channelId) < 0) - { - return -1; - } - - // - // Starting from protocol level 3 client and server - // caches are created in proxy and shared between all - // channels. If remote proxy has older protocol level - // pointers are NULL and channels must create their - // own instances. - // - - channels_[channelId] = new ServerChannel(transports_[channelId], compressor_); - - if (channels_[channelId] == NULL) - { - deallocateTransport(channelId); - - return -1; - } - - increaseChannels(channelId); - - // - // Propagate channel stores and caches to the new - // channel. - // - - channels_[channelId] -> setOpcodes(opcodeStore_); - - channels_[channelId] -> setStores(clientStore_, serverStore_); - - channels_[channelId] -> setCaches(clientCache_, serverCache_); - - int port = atoi(fontServerPort_); - - if (port > 0) - { - channels_[channelId] -> setPorts(port); - } - - // - // Let channel configure itself according - // to control parameters. - // - - channels_[channelId] -> handleConfiguration(); - - // - // Check if we have successfully loaded the - // selected cache and, if not, remove it - // from disk. - // - - handleCheckLoad(); - - return 1; -} - -// -// Check if we still need to drop a channel. We need -// to check this explicitly at the time we receive a -// request to load or save the cache because we could -// receive the control message before having entered -// the function handling the channel events. -// - -int ServerProxy::handleCheckDrop() -{ - T_list channelList = activeChannels_.copyList(); - - for (T_list::iterator j = channelList.begin(); - j != channelList.end(); j++) - { - int channelId = *j; - - if (channels_[channelId] != NULL && - (channels_[channelId] -> getDrop() == 1 || - channels_[channelId] -> getClosing() == 1)) - { - #ifdef TEST - *logofs << "ServerProxy: Dropping the descriptor FD#" - << getFd(channelId) << " channel ID#" - << channelId << ".\n" << logofs_flush; - #endif - - handleDrop(channelId); - } - } - - return 1; -} - -int ServerProxy::handleCheckLoad() -{ - // - // Check if we just created the first X channel - // but the client side didn't tell us to load - // the cache selected at the session negotiation. - // This is very likely because the load operation - // failed at the remote side, for example because - // the cache was invalid or corrupted. - // - - int channelCount = getChannels(channel_x11); - - if (channelCount != 1) - { - return 0; - } - - if (control -> PersistentCacheEnableLoad == 1 && - control -> PersistentCachePath != NULL && - control -> PersistentCacheName != NULL && - isTimestamp(timeouts_.loadTs) == 0) - { - #ifdef WARNING - *logofs << "ServerProxy: WARNING! Cache file '" << control -> PersistentCachePath - << "/" << control -> PersistentCacheName << "' not loaded.\n" - << logofs_flush; - #endif - - // - // Remove the cache file. - // - - #ifdef WARNING - *logofs << "ServerProxy: WARNING! Removing supposedly " - << "incompatible cache '" << control -> PersistentCachePath - << "/" << control -> PersistentCacheName - << "'.\n" << logofs_flush; - #endif - - handleResetPersistentCache(); - } - - return 1; -} - -int ServerProxy::handleLoadFromProxy() -{ - // - // Be sure we drop any confirmed channel. - // - - handleCheckDrop(); - - // - // Check that either no X channel is - // remaining or we are inside a reset. - // - - int channelCount = getChannels(channel_x11); - - if (channelCount > 0) - { - #ifdef PANIC - *logofs << "ServerProxy: PANIC! Protocol violation " - << "in command load with " << channelCount - << " channels.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Protocol violation " - << "in command load from proxy.\n"; - - return -1; - } - else if (handleLoadStores() < 0) - { - #ifdef WARNING - *logofs << "ServerProxy: WARNING! Failed to load content " - << "of persistent cache.\n" << logofs_flush; - #endif - - return -1; - } - - return 1; -} - -int ServerProxy::handleSaveFromProxy() -{ - // - // Be sure we drop any confirmed channel. - // - - handleCheckDrop(); - - // - // Now verify that all channels are gone. - // - - int channelCount = getChannels(channel_x11); - - if (channelCount > 0) - { - #ifdef PANIC - *logofs << "ServerProxy: PANIC! Protocol violation " - << "in command save with " << channelCount - << " channels.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Protocol violation " - << "in command save from proxy.\n"; - - return -1; - } - else if (handleSaveStores() < 0) - { - #ifdef PANIC - *logofs << "ServerProxy: PANIC! Failed to save stores " - << "to persistent cache.\n" << logofs_flush; - #endif - - return -1; - } - - return 1; -} - -int ServerProxy::handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient) const -{ - if (clientStore_ -> saveRequestStores(cachefs, md5StateStream, md5StateClient, - discard_checksum, use_data) < 0) - { - return -1; - } - else if (serverStore_ -> saveReplyStores(cachefs, md5StateStream, md5StateClient, - use_checksum, discard_data) < 0) - { - return -1; - } - else if (serverStore_ -> saveEventStores(cachefs, md5StateStream, md5StateClient, - use_checksum, discard_data) < 0) - { - return -1; - } - - return 1; -} - -int ServerProxy::handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const -{ - if (clientStore_ -> loadRequestStores(cachefs, md5StateStream, - discard_checksum, use_data) < 0) - { - return -1; - } - else if (serverStore_ -> loadReplyStores(cachefs, md5StateStream, - use_checksum, discard_data) < 0) - { - return -1; - } - else if (serverStore_ -> loadEventStores(cachefs, md5StateStream, - use_checksum, discard_data) < 0) - { - return -1; - } - - return 1; -} diff --git a/nxcomp/ServerProxy.h b/nxcomp/ServerProxy.h deleted file mode 100644 index e169c4aec..000000000 --- a/nxcomp/ServerProxy.h +++ /dev/null @@ -1,154 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ServerProxy_H -#define ServerProxy_H - -#include -#include - -#include "Proxy.h" - -#include "Misc.h" -#include "ChannelEndPoint.h" - -// -// Set the verbosity level. -// - -#undef TEST -#undef DEBUG - -class ServerProxy : public Proxy -{ - public: - - ServerProxy(int proxyFd); - - virtual ~ServerProxy(); - - virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, - sockaddr *xServerAddr, unsigned int xServerAddrLength); - - virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort, - ChannelEndPoint &smbServerPort, - ChannelEndPoint &mediaServerPort, - ChannelEndPoint &httpServerPort, - const char *fontServerPort); - - protected: - - // - // Create a new channel. - // - - virtual int handleNewConnection(T_channel_type type, int clientFd); - - virtual int handleNewConnectionFromProxy(T_channel_type type, int channelId); - - virtual int handleNewAgentConnection(Agent *agent); - - virtual int handleNewXConnection(int clientFd); - - virtual int handleNewXConnectionFromProxy(int channelId); - - // - // Implement persistence according - // to our proxy mode. - // - - virtual int handleLoad(T_load_type type) - { - return 0; - } - - virtual int handleSave() - { - return 0; - } - - virtual int handleAsyncEvents() - { - return 0; - } - - virtual int handleLoadFromProxy(); - virtual int handleSaveFromProxy(); - - virtual int handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient) const; - - virtual int handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const; - - int handleCheckDrop(); - int handleCheckLoad(); - - // - // Utility function used to realize - // a new connection. - // - - protected: - - virtual int checkLocalChannelMap(int channelId) - { - // Since ProtoStep7 (#issue 108) - return ((channelId & control -> ChannelMask) == 0); - } - - private: - - // FIXME: Use a ChannelEndPoint object also for the X server! - int xServerAddrFamily_; - sockaddr *xServerAddr_; - unsigned int xServerAddrLength_; - - // - // This is the name of the X display where - // we are going to forward connections. - // - - char *xServerDisplay_; - - // - // Ports where to forward extended services' - // TCP connections. - // - - ChannelEndPoint cupsServerPort_; - ChannelEndPoint smbServerPort_; - ChannelEndPoint mediaServerPort_; - ChannelEndPoint httpServerPort_; - - // - // It will have to be passed to the channel - // so that it can set the port where the - // font server connections are tunneled. - // - - char *fontServerPort_; -}; - -#endif /* ServerProxy_H */ diff --git a/nxcomp/ServerReadBuffer.cpp b/nxcomp/ServerReadBuffer.cpp deleted file mode 100644 index 5bd9bb60f..000000000 --- a/nxcomp/ServerReadBuffer.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ServerReadBuffer.h" -#include "ServerChannel.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -unsigned int ServerReadBuffer::suggestedLength(unsigned int pendingLength) -{ - // - // Always read all the data that - // is available. - // - - int readable = transport_ -> readable(); - - unsigned int readLength = (readable == -1 ? 0 : (unsigned int) readable); - - if (readLength < pendingLength) - { - readLength = pendingLength; - } - - // - // Even if the readable data is not - // enough to make a complete message, - // resize the buffer to accommodate - // it all. - // - - if (pendingLength < remaining_) - { - readLength = remaining_; - } - - return readLength; -} - -int ServerReadBuffer::locateMessage(const unsigned char *start, - const unsigned char *end, - unsigned int &controlLength, - unsigned int &dataLength, - unsigned int &trailerLength) -{ - unsigned int size = end - start; - - #ifdef TEST - *logofs << "ServerReadBuffer: Locating message for FD#" - << transport_ -> fd() << " with " << size - << " bytes.\n" << logofs_flush; - #endif - - if (firstMessage_) - { - if (size < 8) - { - remaining_ = 8 - size; - - #ifdef TEST - *logofs << "ServerReadBuffer: No message was located " - << "with remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - - dataLength = 8 + (GetUINT(start + 6, bigEndian_) << 2); - } - else - { - if (size < 32) - { - remaining_ = 32 - size; - - #ifdef TEST - *logofs << "ServerReadBuffer: No message was located " - << "with remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - - if (*start == 1) - { - dataLength = 32 + (GetULONG(start + 4, bigEndian_) << 2); - } - else - { - dataLength = 32; - } - - if (dataLength < 32) - { - #ifdef TEST - *logofs << "ServerReadBuffer: WARNING! Assuming length 32 " - << "for suspicious message of length " << dataLength - << ".\n" << logofs_flush; - #endif - - dataLength = 32; - } - } - - #ifdef TEST - *logofs << "ServerReadBuffer: Length of the next message is " - << dataLength << ".\n" << logofs_flush; - #endif - - if (size < dataLength) - { - remaining_ = dataLength - size; - - #ifdef TEST - *logofs << "ServerReadBuffer: No message was located " - << "with remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - - firstMessage_ = 0; - - controlLength = 0; - trailerLength = 0; - - remaining_ = 0; - - #ifdef TEST - *logofs << "ServerReadBuffer: Located message with " - << "remaining " << remaining_ << ".\n" - << logofs_flush; - #endif - - return 1; -} - -// -// Check if the data already read contains a -// message matching the opcode and sequence, -// starting at the given offset. -// - -unsigned char *ServerReadBuffer::peekMessage(unsigned int &offset, unsigned char opcode, - unsigned short sequence) -{ - #ifdef TEST - *logofs << "ServerReadBuffer: Peeking message " - << "for FD#" << transport_ -> fd() << " with size " - << length_ << " offset " << offset << " opcode " - << (unsigned int) opcode << " and sequence " - << sequence << ".\n" << logofs_flush; - #endif - - if (firstMessage_) - { - return NULL; - } - - unsigned char *next = buffer_ + start_ + offset; - unsigned char *end = buffer_ + start_ + length_; - - int found = 0; - - while (end - next >= 32) - { - #ifdef DEBUG - *logofs << "ServerReadBuffer: Checking opcode " - << (unsigned int) *next << " sequence " - << GetUINT(next + 2, bigEndian_) - << " at " << next - buffer_ + start_ - << ".\n" << logofs_flush; - #endif - - if (*next == opcode && GetUINT(next + 2, bigEndian_) == sequence) - { - found = 1; - - break; - } - else if (*next == 1) - { - next += (32 + (GetULONG(next + 4, bigEndian_) << 2)); - } - else - { - next += 32; - } - } - - offset = next - buffer_ + start_; - - if (found == 1) - { - #ifdef TEST - *logofs << "ServerReadBuffer: Found message at " - << "offset " << next - buffer_ + start_ - << ".\n" << logofs_flush; - #endif - - return next; - } - - #ifdef TEST - *logofs << "ServerReadBuffer: Quitting loop at " - << "offset " << next - buffer_ + start_ - << ".\n" << logofs_flush; - #endif - - return NULL; -} diff --git a/nxcomp/ServerReadBuffer.h b/nxcomp/ServerReadBuffer.h deleted file mode 100644 index d6c207ead..000000000 --- a/nxcomp/ServerReadBuffer.h +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ServerReadBuffer_H -#define ServerReadBuffer_H - -#include "ReadBuffer.h" -#include "Control.h" - -class ServerChannel; - -class ServerReadBuffer : public ReadBuffer -{ - public: - - ServerReadBuffer(Transport *transport, ServerChannel *channel) - - : ReadBuffer(transport), firstMessage_(1), channel_(channel) - { - } - - virtual ~ServerReadBuffer() - { - } - - void setBigEndian(int flag) - { - bigEndian_ = flag; - } - - unsigned char *peekMessage(unsigned int &offset, unsigned char opcode, - unsigned short sequence); - - protected: - - virtual unsigned int suggestedLength(unsigned int pendingLength); - - virtual int locateMessage(const unsigned char *start, - const unsigned char *end, - unsigned int &controlLength, - unsigned int &dataLength, - unsigned int &trailerLength); - - int bigEndian_; - - int firstMessage_; - - ServerChannel *channel_; -}; - -#endif /* ServerReadBuffer_H */ diff --git a/nxcomp/ServerStore.cpp b/nxcomp/ServerStore.cpp deleted file mode 100644 index 0fb17d974..000000000 --- a/nxcomp/ServerStore.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ServerStore.h" - -// -// Cached reply classes. -// - -#include "GetImageReply.h" -#include "ListFontsReply.h" -#include "QueryFontReply.h" -#include "GetPropertyReply.h" -#include "GenericReply.h" - -// -// Set the verbosity level. -// - -#define WARNING -#define PANIC -#undef TEST - -ServerStore::ServerStore(StaticCompressor *compressor) -{ - if (logofs == NULL) - { - logofs = &cout; - } - - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - replies_[i] = NULL; - events_[i] = NULL; - } - - replies_[X_ListFonts] = new ListFontsReplyStore(compressor); - replies_[X_QueryFont] = new QueryFontReplyStore(compressor); - replies_[X_GetImage] = new GetImageReplyStore(compressor); - replies_[X_GetProperty] = new GetPropertyReplyStore(compressor); - - replies_[X_NXInternalGenericReply] = new GenericReplyStore(compressor); -} - -ServerStore::~ServerStore() -{ - if (logofs == NULL) - { - logofs = &cout; - } - - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - delete replies_[i]; - delete events_[i]; - } -} - -int ServerStore::saveReplyStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient, T_checksum_action checksumAction, - T_data_action dataAction) const -{ - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - if (replies_[i] != NULL && - replies_[i] -> saveStore(cachefs, md5StateStream, md5StateClient, - checksumAction, dataAction, - storeBigEndian()) < 0) - { - #ifdef PANIC - *logofs << "ServerStore: PANIC! Error saving reply store " - << "for OPCODE#" << (unsigned int) i << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error saving reply store " - << "for opcode '" << (unsigned int) i << "'.\n"; - - return -1; - } - } - - return 1; -} - -int ServerStore::saveEventStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient, T_checksum_action checksumAction, - T_data_action dataAction) const -{ - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - if (events_[i] != NULL && - events_[i] -> saveStore(cachefs, md5StateStream, md5StateClient, - checksumAction, dataAction, - storeBigEndian()) < 0) - { - #ifdef PANIC - *logofs << "ServerStore: PANIC! Error saving event store " - << "for OPCODE#" << (unsigned int) i << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Error saving event store " - << "for opcode '" << (unsigned int) i << "'.\n"; - - return -1; - } - } - - return 1; -} - -int ServerStore::loadReplyStores(istream *cachefs, md5_state_t *md5StateStream, - T_checksum_action checksumAction, T_data_action dataAction) const -{ - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - if (replies_[i] != NULL && - replies_[i] -> loadStore(cachefs, md5StateStream, - checksumAction, dataAction, - storeBigEndian()) < 0) - { - #ifdef PANIC - *logofs << "ServerStore: PANIC! Error loading reply store " - << "for OPCODE#" << (unsigned int) i << ".\n" - << logofs_flush; - #endif - - return -1; - } - } - - return 1; -} - -int ServerStore::loadEventStores(istream *cachefs, md5_state_t *md5StateStream, - T_checksum_action checksumAction, T_data_action dataAction) const -{ - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - if (events_[i] != NULL && - events_[i] -> loadStore(cachefs, md5StateStream, - checksumAction, dataAction, - storeBigEndian()) < 0) - { - #ifdef PANIC - *logofs << "ServerStore: PANIC! Error loading event store " - << "for OPCODE#" << (unsigned int) i << ".\n" - << logofs_flush; - #endif - - return -1; - } - } - - return 1; -} diff --git a/nxcomp/ServerStore.h b/nxcomp/ServerStore.h deleted file mode 100644 index dbbb968e5..000000000 --- a/nxcomp/ServerStore.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ServerStore_H -#define ServerStore_H - -#include "Message.h" - -#include "ChannelStore.h" - -class StaticCompressor; - -class ServerStore : public ChannelStore -{ - public: - - ServerStore(StaticCompressor *compressor); - - virtual ~ServerStore(); - - MessageStore *getReplyStore(unsigned char opcode) const - { - return replies_[opcode]; - } - - MessageStore *getEventStore(unsigned char opcode) const - { - return events_[opcode]; - } - - // - // Actually save the message store - // to disk according to proxy mode. - // - - int saveReplyStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient, T_checksum_action checksumAction, - T_data_action dataAction) const; - - int saveEventStores(ostream *cachefs, md5_state_t *md5StateStream, - md5_state_t *md5StateClient, T_checksum_action checksumAction, - T_data_action dataAction) const; - - - int loadReplyStores(istream *cachefs, md5_state_t *md5StateStream, - T_checksum_action checksumAction, T_data_action dataAction) const; - - int loadEventStores(istream *cachefs, md5_state_t *md5StateStream, - T_checksum_action checksumAction, T_data_action dataAction) const; - - private: - - // - // A server store contains replies and events. - // - - MessageStore *replies_[CHANNEL_STORE_OPCODE_LIMIT]; - MessageStore *events_[CHANNEL_STORE_OPCODE_LIMIT]; -}; - -#endif /* ServerStore_H */ diff --git a/nxcomp/SetClipRectangles.cpp b/nxcomp/SetClipRectangles.cpp deleted file mode 100644 index 164ead006..000000000 --- a/nxcomp/SetClipRectangles.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "SetClipRectangles.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int SetClipRectanglesStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; - - // - // Here is the fingerprint. - // - - setClipRectangles -> ordering = *(buffer + 1); - - setClipRectangles -> gcontext = GetULONG(buffer + 4, bigEndian); - - setClipRectangles -> x_origin = GetUINT(buffer + 8, bigEndian); - setClipRectangles -> y_origin = GetUINT(buffer + 10, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int SetClipRectanglesStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; - - // - // Fill all the message's fields. - // - - *(buffer + 1) = setClipRectangles -> ordering; - - PutULONG(setClipRectangles -> gcontext, buffer + 4, bigEndian); - - PutUINT(setClipRectangles -> x_origin, buffer + 8, bigEndian); - PutUINT(setClipRectangles -> y_origin, buffer + 10, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void SetClipRectanglesStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; - - *logofs << name() << ": Identity ordering " << (unsigned int) setClipRectangles -> ordering - << ", gcontext " << setClipRectangles -> gcontext << ", x_origin " - << setClipRectangles -> x_origin << ", y_origin " - << setClipRectangles -> y_origin << ", size " - << setClipRectangles -> size_ << ".\n" << logofs_flush; - #endif -} - -void SetClipRectanglesStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 1, 1); - md5_append(md5_state_, buffer + 8, 4); -} - -void SetClipRectanglesStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; - SetClipRectanglesMessage *cachedSetClipRectangles = (SetClipRectanglesMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " << setClipRectangles -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeXidValue(setClipRectangles -> gcontext, clientCache -> gcCache); - - cachedSetClipRectangles -> gcontext = setClipRectangles -> gcontext; -} - -void SetClipRectanglesStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - decodeBuffer.decodeXidValue(value, clientCache -> gcCache); - - setClipRectangles -> gcontext = value; - - #ifdef DEBUG - *logofs << name() << ": Decoded value " << setClipRectangles -> gcontext - << " as gcontext field.\n" << logofs_flush; - #endif -} diff --git a/nxcomp/SetClipRectangles.h b/nxcomp/SetClipRectangles.h deleted file mode 100644 index a2245360c..000000000 --- a/nxcomp/SetClipRectangles.h +++ /dev/null @@ -1,187 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef SetClipRectangles_H -#define SetClipRectangles_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define SETCLIPRECTANGLES_ENABLE_CACHE 1 -#define SETCLIPRECTANGLES_ENABLE_DATA 0 -#define SETCLIPRECTANGLES_ENABLE_SPLIT 0 -#define SETCLIPRECTANGLES_ENABLE_COMPRESS 0 - -#define SETCLIPRECTANGLES_DATA_LIMIT 2048 -#define SETCLIPRECTANGLES_DATA_OFFSET 12 - -#define SETCLIPRECTANGLES_CACHE_SLOTS 3000 -#define SETCLIPRECTANGLES_CACHE_THRESHOLD 3 -#define SETCLIPRECTANGLES_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class SetClipRectanglesMessage : public Message -{ - friend class SetClipRectanglesStore; - - public: - - SetClipRectanglesMessage() - { - } - - ~SetClipRectanglesMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char ordering; - unsigned int gcontext; - unsigned short x_origin; - unsigned short y_origin; -}; - -class SetClipRectanglesStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - SetClipRectanglesStore() : MessageStore() - { - enableCache = SETCLIPRECTANGLES_ENABLE_CACHE; - enableData = SETCLIPRECTANGLES_ENABLE_DATA; - enableSplit = SETCLIPRECTANGLES_ENABLE_SPLIT; - enableCompress = SETCLIPRECTANGLES_ENABLE_COMPRESS; - - dataLimit = SETCLIPRECTANGLES_DATA_LIMIT; - dataOffset = SETCLIPRECTANGLES_DATA_OFFSET; - - cacheSlots = SETCLIPRECTANGLES_CACHE_SLOTS; - cacheThreshold = SETCLIPRECTANGLES_CACHE_THRESHOLD; - cacheLowerThreshold = SETCLIPRECTANGLES_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~SetClipRectanglesStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "SetClipRectangles"; - } - - virtual unsigned char opcode() const - { - return X_SetClipRectangles; - } - - virtual unsigned int storage() const - { - return sizeof(SetClipRectanglesMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new SetClipRectanglesMessage(); - } - - virtual Message *create(const Message &message) const - { - return new SetClipRectanglesMessage((const SetClipRectanglesMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (SetClipRectanglesMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* SetClipRectangles_H */ diff --git a/nxcomp/SetUnpackAlpha.cpp b/nxcomp/SetUnpackAlpha.cpp deleted file mode 100644 index cf09074e3..000000000 --- a/nxcomp/SetUnpackAlpha.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "SetUnpackAlpha.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -SetUnpackAlphaStore::SetUnpackAlphaStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = SETUNPACKALPHA_ENABLE_CACHE; - enableData = SETUNPACKALPHA_ENABLE_DATA; - enableCompress = SETUNPACKALPHA_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = SETUNPACKALPHA_DATA_LIMIT; - dataOffset = SETUNPACKALPHA_DATA_OFFSET_IF_PROTO_STEP_7; - - cacheSlots = SETUNPACKALPHA_CACHE_SLOTS; - cacheThreshold = SETUNPACKALPHA_CACHE_THRESHOLD; - cacheLowerThreshold = SETUNPACKALPHA_CACHE_LOWER_THRESHOLD; - - // Since ProtoStep8 (#issue 108) - enableSplit = SETUNPACKALPHA_ENABLE_SPLIT_IF_PROTO_STEP_8; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -SetUnpackAlphaStore::~SetUnpackAlphaStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int SetUnpackAlphaStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; - #endif - - // - // Encode the source length first because - // we need it to determine the size of - // the output buffer. - // - - // SrcLength. - encodeBuffer.encodeValue(GetULONG(buffer + 8, bigEndian), 32, 9); - - // Client. - encodeBuffer.encodeCachedValue(*(buffer + 1), 8, - clientCache -> resourceCache); - // Method. - encodeBuffer.encodeCachedValue(*(buffer + 4), 8, - clientCache -> methodCache); - // DstLength. - encodeBuffer.encodeValue(GetULONG(buffer + 12, bigEndian), 32, 9); - - #ifdef DEBUG - *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int SetUnpackAlphaStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; - #endif - - unsigned int value; - unsigned char cValue; - - // SrcLength. - decodeBuffer.decodeValue(value, 32, 9); - - size = RoundUp4(value) + 16; - - buffer = writeBuffer -> addMessage(size); - - PutULONG(value, buffer + 8, bigEndian); - - // Client. - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> resourceCache); - - *(buffer + 1) = cValue; - - // Method. - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> methodCache); - - *(buffer + 4) = cValue; - - // DstLength. - decodeBuffer.decodeValue(value, 32, 9); - - PutULONG(value, buffer + 12, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int SetUnpackAlphaStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; - - setUnpackAlpha -> client = *(buffer + 1); - setUnpackAlpha -> method = *(buffer + 4); - - setUnpackAlpha -> src_length = GetULONG(buffer + 8, bigEndian); - setUnpackAlpha -> dst_length = GetULONG(buffer + 12, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int SetUnpackAlphaStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; - - *(buffer + 1) = setUnpackAlpha -> client; - *(buffer + 4) = setUnpackAlpha -> method; - - PutULONG(setUnpackAlpha -> src_length, buffer + 8, bigEndian); - PutULONG(setUnpackAlpha -> dst_length, buffer + 12, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void SetUnpackAlphaStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; - - *logofs << name() << ": Identity client " - << (unsigned int) setUnpackAlpha -> client << " method " - << (unsigned int) setUnpackAlpha -> method << " source length " - << setUnpackAlpha -> src_length << " destination length " - << setUnpackAlpha -> dst_length << " size " - << setUnpackAlpha -> size_ << ".\n"; - - #endif -} - -void SetUnpackAlphaStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Include the pack method and the source - // and destination length. - // - - md5_append(md5_state_, buffer + 4, 1); - md5_append(md5_state_, buffer + 8, 8); -} - -void SetUnpackAlphaStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; - SetUnpackAlphaMessage *cachedSetUnpackAlpha = (SetUnpackAlphaMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(setUnpackAlpha -> client, 8, - clientCache -> resourceCache); - - cachedSetUnpackAlpha -> client = setUnpackAlpha -> client; -} - -void SetUnpackAlphaStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(setUnpackAlpha -> client, 8, - clientCache -> resourceCache); -} diff --git a/nxcomp/SetUnpackAlpha.h b/nxcomp/SetUnpackAlpha.h deleted file mode 100644 index 54714efaa..000000000 --- a/nxcomp/SetUnpackAlpha.h +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef SetUnpackAlpha_H -#define SetUnpackAlpha_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define SETUNPACKALPHA_ENABLE_CACHE 1 -#define SETUNPACKALPHA_ENABLE_DATA 1 - -#define SETUNPACKALPHA_DATA_LIMIT 16384 - -#define SETUNPACKALPHA_CACHE_SLOTS 2000 -#define SETUNPACKALPHA_CACHE_THRESHOLD 10 -#define SETUNPACKALPHA_CACHE_LOWER_THRESHOLD 5 - -#define SETUNPACKALPHA_DATA_OFFSET_IF_PROTO_STEP_7 16 -#define SETUNPACKALPHA_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -#define SETUNPACKALPHA_ENABLE_SPLIT_IF_PROTO_STEP_8 0 - -// -// The message class. -// - -class SetUnpackAlphaMessage : public Message -{ - friend class SetUnpackAlphaStore; - - public: - - SetUnpackAlphaMessage() - { - } - - ~SetUnpackAlphaMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char client; - unsigned char method; - - unsigned int src_length; - unsigned int dst_length; -}; - -class SetUnpackAlphaStore : public MessageStore -{ - public: - - SetUnpackAlphaStore(StaticCompressor *compressor); - - virtual ~SetUnpackAlphaStore(); - - virtual const char *name() const - { - return "SetUnpackAlpha"; - } - - virtual unsigned char opcode() const - { - return X_NXSetUnpackAlpha; - } - - virtual unsigned int storage() const - { - return sizeof(SetUnpackAlphaMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new SetUnpackAlphaMessage(); - } - - virtual Message *create(const Message &message) const - { - return new SetUnpackAlphaMessage((const SetUnpackAlphaMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (SetUnpackAlphaMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* SetUnpackAlpha_H */ diff --git a/nxcomp/SetUnpackColormap.cpp b/nxcomp/SetUnpackColormap.cpp deleted file mode 100644 index b44a7cf13..000000000 --- a/nxcomp/SetUnpackColormap.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "SetUnpackColormap.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -SetUnpackColormapStore::SetUnpackColormapStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = SETUNPACKCOLORMAP_ENABLE_CACHE; - enableData = SETUNPACKCOLORMAP_ENABLE_DATA; - enableCompress = SETUNPACKCOLORMAP_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = SETUNPACKCOLORMAP_DATA_LIMIT; - dataOffset = SETUNPACKCOLORMAP_DATA_OFFSET_IF_PROTO_STEP_7; - - cacheSlots = SETUNPACKCOLORMAP_CACHE_SLOTS; - cacheThreshold = SETUNPACKCOLORMAP_CACHE_THRESHOLD; - cacheLowerThreshold = SETUNPACKCOLORMAP_CACHE_LOWER_THRESHOLD; - - // Since ProtoStep8 (#issue 108) - enableSplit = SETUNPACKCOLORMAP_ENABLE_SPLIT_IF_PROTO_STEP_8; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -SetUnpackColormapStore::~SetUnpackColormapStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int SetUnpackColormapStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; - #endif - - // - // Encode the source length first because - // we need it to determine the size of - // the output buffer. - // - - // SrcLength. - encodeBuffer.encodeValue(GetULONG(buffer + 8, bigEndian), 32, 9); - - // Client. - encodeBuffer.encodeCachedValue(*(buffer + 1), 8, - clientCache -> resourceCache); - // Method. - encodeBuffer.encodeCachedValue(*(buffer + 4), 8, - clientCache -> methodCache); - // DstLength. - encodeBuffer.encodeValue(GetULONG(buffer + 12, bigEndian), 32, 9); - - #ifdef DEBUG - *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int SetUnpackColormapStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; - #endif - - unsigned int value; - unsigned char cValue; - - // SrcLength. - decodeBuffer.decodeValue(value, 32, 9); - - size = RoundUp4(value) + 16; - - buffer = writeBuffer -> addMessage(size); - - PutULONG(value, buffer + 8, bigEndian); - - // Client. - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> resourceCache); - - *(buffer + 1) = cValue; - - // Method. - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> methodCache); - - *(buffer + 4) = cValue; - - // DstLength. - decodeBuffer.decodeValue(value, 32, 9); - - PutULONG(value, buffer + 12, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int SetUnpackColormapStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; - - setUnpackColormap -> client = *(buffer + 1); - setUnpackColormap -> method = *(buffer + 4); - - setUnpackColormap -> src_length = GetULONG(buffer + 8, bigEndian); - setUnpackColormap -> dst_length = GetULONG(buffer + 12, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int SetUnpackColormapStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; - - *(buffer + 1) = setUnpackColormap -> client; - *(buffer + 4) = setUnpackColormap -> method; - - PutULONG(setUnpackColormap -> src_length, buffer + 8, bigEndian); - PutULONG(setUnpackColormap -> dst_length, buffer + 12, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void SetUnpackColormapStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; - - *logofs << name() << ": Identity client " - << (unsigned int) setUnpackColormap -> client << " method " - << (unsigned int) setUnpackColormap -> method << " source length " - << setUnpackColormap -> src_length << " destination length " - << setUnpackColormap -> dst_length << " size " - << setUnpackColormap -> size_ << ".\n"; - - #endif -} - -void SetUnpackColormapStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Include the pack method and the source - // and destination length. - // - - md5_append(md5_state_, buffer + 4, 1); - md5_append(md5_state_, buffer + 8, 8); -} - -void SetUnpackColormapStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; - SetUnpackColormapMessage *cachedSetUnpackColormap = (SetUnpackColormapMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - encodeBuffer.encodeCachedValue(setUnpackColormap -> client, 8, - clientCache -> resourceCache); - - cachedSetUnpackColormap -> client = setUnpackColormap -> client; -} - -void SetUnpackColormapStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(setUnpackColormap -> client, 8, - clientCache -> resourceCache); -} diff --git a/nxcomp/SetUnpackColormap.h b/nxcomp/SetUnpackColormap.h deleted file mode 100644 index 779366531..000000000 --- a/nxcomp/SetUnpackColormap.h +++ /dev/null @@ -1,162 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef SetUnpackColormap_H -#define SetUnpackColormap_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define SETUNPACKCOLORMAP_ENABLE_CACHE 1 -#define SETUNPACKCOLORMAP_ENABLE_DATA 1 - -#define SETUNPACKCOLORMAP_DATA_LIMIT 4096 - -#define SETUNPACKCOLORMAP_CACHE_SLOTS 2000 -#define SETUNPACKCOLORMAP_CACHE_THRESHOLD 5 -#define SETUNPACKCOLORMAP_CACHE_LOWER_THRESHOLD 0 - -#define SETUNPACKCOLORMAP_DATA_OFFSET_IF_PROTO_STEP_7 16 -#define SETUNPACKCOLORMAP_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -#define SETUNPACKCOLORMAP_ENABLE_SPLIT_IF_PROTO_STEP_8 0 - -// -// The message class. -// - -class SetUnpackColormapMessage : public Message -{ - friend class SetUnpackColormapStore; - - public: - - SetUnpackColormapMessage() - { - } - - ~SetUnpackColormapMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char client; - unsigned char method; - - unsigned int src_length; - unsigned int dst_length; -}; - -class SetUnpackColormapStore : public MessageStore -{ - public: - - SetUnpackColormapStore(StaticCompressor *compressor); - - virtual ~SetUnpackColormapStore(); - - virtual const char *name() const - { - return "SetUnpackColormap"; - } - - virtual unsigned char opcode() const - { - return X_NXSetUnpackColormap; - } - - virtual unsigned int storage() const - { - return sizeof(SetUnpackColormapMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new SetUnpackColormapMessage(); - } - - virtual Message *create(const Message &message) const - { - return new SetUnpackColormapMessage((const SetUnpackColormapMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (SetUnpackColormapMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* SetUnpackColormap_H */ diff --git a/nxcomp/SetUnpackGeometry.cpp b/nxcomp/SetUnpackGeometry.cpp deleted file mode 100644 index 49fa4344e..000000000 --- a/nxcomp/SetUnpackGeometry.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "SetUnpackGeometry.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -SetUnpackGeometryStore::SetUnpackGeometryStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = SETUNPACKGEOMETRY_ENABLE_CACHE; - enableData = SETUNPACKGEOMETRY_ENABLE_DATA; - enableSplit = SETUNPACKGEOMETRY_ENABLE_SPLIT; - enableCompress = SETUNPACKGEOMETRY_ENABLE_COMPRESS; - - dataLimit = SETUNPACKGEOMETRY_DATA_LIMIT; - dataOffset = SETUNPACKGEOMETRY_DATA_OFFSET; - - cacheSlots = SETUNPACKGEOMETRY_CACHE_SLOTS; - cacheThreshold = SETUNPACKGEOMETRY_CACHE_THRESHOLD; - cacheLowerThreshold = SETUNPACKGEOMETRY_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -SetUnpackGeometryStore::~SetUnpackGeometryStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int SetUnpackGeometryStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(*(buffer + 1), 8, - clientCache -> resourceCache); - - const unsigned char *nextChar = buffer + 4; - - for (int i = 0; i < 6; i++) - { - encodeBuffer.encodeCachedValue(*nextChar++, 8, - clientCache -> depthCache); - } - - encodeBuffer.encodeValue(GetULONG(buffer + 12, bigEndian), 32); - encodeBuffer.encodeValue(GetULONG(buffer + 16, bigEndian), 32); - encodeBuffer.encodeValue(GetULONG(buffer + 20, bigEndian), 32); - - #ifdef DEBUG - *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int SetUnpackGeometryStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; - #endif - - size = 24; - buffer = writeBuffer -> addMessage(size); - - unsigned char cValue; - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> resourceCache); - *(buffer + 1) = cValue; - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - *(buffer + 4) = cValue; - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - *(buffer + 5) = cValue; - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - *(buffer + 6) = cValue; - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - *(buffer + 7) = cValue; - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - *(buffer + 8) = cValue; - - decodeBuffer.decodeCachedValue(cValue, 8, - clientCache -> depthCache); - *(buffer + 9) = cValue; - - unsigned int value; - - decodeBuffer.decodeValue(value, 32); - PutULONG(value, buffer + 12, bigEndian); - - decodeBuffer.decodeValue(value, 32); - PutULONG(value, buffer + 16, bigEndian); - - decodeBuffer.decodeValue(value, 32); - PutULONG(value, buffer + 20, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int SetUnpackGeometryStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; - - setUnpackGeometry -> client = *(buffer + 1); - - setUnpackGeometry -> depth_1_bpp = *(buffer + 4); - setUnpackGeometry -> depth_4_bpp = *(buffer + 5); - setUnpackGeometry -> depth_8_bpp = *(buffer + 6); - setUnpackGeometry -> depth_16_bpp = *(buffer + 7); - setUnpackGeometry -> depth_24_bpp = *(buffer + 8); - setUnpackGeometry -> depth_32_bpp = *(buffer + 9); - - setUnpackGeometry -> red_mask = GetULONG(buffer + 12, bigEndian); - setUnpackGeometry -> green_mask = GetULONG(buffer + 16, bigEndian); - setUnpackGeometry -> blue_mask = GetULONG(buffer + 20, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -int SetUnpackGeometryStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; - - *(buffer + 1) = setUnpackGeometry -> client; - - *(buffer + 4) = setUnpackGeometry -> depth_1_bpp; - *(buffer + 5) = setUnpackGeometry -> depth_4_bpp; - *(buffer + 6) = setUnpackGeometry -> depth_8_bpp; - *(buffer + 7) = setUnpackGeometry -> depth_16_bpp; - *(buffer + 8) = setUnpackGeometry -> depth_24_bpp; - *(buffer + 9) = setUnpackGeometry -> depth_32_bpp; - - PutULONG(setUnpackGeometry -> red_mask, buffer + 12, bigEndian); - PutULONG(setUnpackGeometry -> green_mask, buffer + 16, bigEndian); - PutULONG(setUnpackGeometry -> blue_mask, buffer + 20, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; - #endif - - return 1; -} - -void SetUnpackGeometryStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; - - *logofs << name() << ": Identity client " - << (unsigned) setUnpackGeometry -> client << " depth_1_bpp " - << (unsigned) setUnpackGeometry -> depth_1_bpp << " depth_4_bpp " - << (unsigned int) setUnpackGeometry -> depth_4_bpp << " depth_8_bpp " - << (unsigned int) setUnpackGeometry -> depth_8_bpp << " depth_16_bpp " - << (unsigned int) setUnpackGeometry -> depth_16_bpp << " depth_24_bpp " - << (unsigned int) setUnpackGeometry -> depth_24_bpp << " depth_32_bpp " - << (unsigned int) setUnpackGeometry -> depth_32_bpp - - << " red_mask " << setUnpackGeometry -> red_mask - << " green_mask " << setUnpackGeometry -> green_mask - << " blue_mask " << setUnpackGeometry -> blue_mask - - << " size " << setUnpackGeometry -> size_ << ".\n"; - - #endif -} - -void SetUnpackGeometryStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 4, 6); - md5_append(md5_state_, buffer + 12, 12); -} - -void SetUnpackGeometryStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; - SetUnpackGeometryMessage *cachedSetUnpackGeometry = (SetUnpackGeometryMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef TEST - *logofs << name() << ": Encoding value " - << (unsigned int) setUnpackGeometry -> client - << " as client field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue(setUnpackGeometry -> client, 8, - clientCache -> resourceCache); - - cachedSetUnpackGeometry -> client = setUnpackGeometry -> client; -} - -void SetUnpackGeometryStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - decodeBuffer.decodeCachedValue(setUnpackGeometry -> client, 8, - clientCache -> resourceCache); - - #ifdef DEBUG - *logofs << name() << ": Decoded value " - << (unsigned int) setUnpackGeometry -> client - << " as client field.\n" << logofs_flush; - #endif -} diff --git a/nxcomp/SetUnpackGeometry.h b/nxcomp/SetUnpackGeometry.h deleted file mode 100644 index 96104f57f..000000000 --- a/nxcomp/SetUnpackGeometry.h +++ /dev/null @@ -1,167 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef SetUnpackGeometry_H -#define SetUnpackGeometry_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define SETUNPACKGEOMETRY_ENABLE_CACHE 1 -#define SETUNPACKGEOMETRY_ENABLE_DATA 0 -#define SETUNPACKGEOMETRY_ENABLE_SPLIT 0 -#define SETUNPACKGEOMETRY_ENABLE_COMPRESS 0 - -#define SETUNPACKGEOMETRY_DATA_LIMIT 24 -#define SETUNPACKGEOMETRY_DATA_OFFSET 24 - -#define SETUNPACKGEOMETRY_CACHE_SLOTS 20 -#define SETUNPACKGEOMETRY_CACHE_THRESHOLD 1 -#define SETUNPACKGEOMETRY_CACHE_LOWER_THRESHOLD 0 - -// -// The message class. -// - -class SetUnpackGeometryMessage : public Message -{ - friend class SetUnpackGeometryStore; - - public: - - SetUnpackGeometryMessage() - { - } - - ~SetUnpackGeometryMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned char client; - - unsigned char depth_1_bpp; - unsigned char depth_4_bpp; - unsigned char depth_8_bpp; - unsigned char depth_16_bpp; - unsigned char depth_24_bpp; - unsigned char depth_32_bpp; - - unsigned int red_mask; - unsigned int green_mask; - unsigned int blue_mask; -}; - -class SetUnpackGeometryStore : public MessageStore -{ - public: - - SetUnpackGeometryStore(StaticCompressor *compressor); - - virtual ~SetUnpackGeometryStore(); - - virtual const char *name() const - { - return "SetUnpackGeometry"; - } - - virtual unsigned char opcode() const - { - return X_NXSetUnpackGeometry; - } - - virtual unsigned int storage() const - { - return sizeof(SetUnpackGeometryMessage); - } - - // - // Message handling methods. - // - - protected: - - virtual Message *create() const - { - return new SetUnpackGeometryMessage(); - } - - virtual Message *create(const Message &message) const - { - return new SetUnpackGeometryMessage((const SetUnpackGeometryMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (SetUnpackGeometryMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* SetUnpackGeometry_H */ diff --git a/nxcomp/ShapeExtension.cpp b/nxcomp/ShapeExtension.cpp deleted file mode 100644 index be3b9a903..000000000 --- a/nxcomp/ShapeExtension.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "ShapeExtension.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "WriteBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Constructors and destructors. -// - -ShapeExtensionStore::ShapeExtensionStore(StaticCompressor *compressor) - - : MessageStore(compressor) -{ - enableCache = SHAPEEXTENSION_ENABLE_CACHE; - enableData = SHAPEEXTENSION_ENABLE_DATA; - enableSplit = SHAPEEXTENSION_ENABLE_SPLIT; - - // Since ProtoStep7 (#issue 108) - enableCompress = SHAPEEXTENSION_ENABLE_COMPRESS_IF_PROTO_STEP_7; - - dataLimit = SHAPEEXTENSION_DATA_LIMIT; - dataOffset = SHAPEEXTENSION_DATA_OFFSET; - - cacheSlots = SHAPEEXTENSION_CACHE_SLOTS; - cacheThreshold = SHAPEEXTENSION_CACHE_THRESHOLD; - cacheLowerThreshold = SHAPEEXTENSION_CACHE_LOWER_THRESHOLD; - - opcode_ = X_NXInternalShapeExtension; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; -} - -ShapeExtensionStore::~ShapeExtensionStore() -{ - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); -} - -// -// Here are the methods to handle messages' content. -// - -int ShapeExtensionStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const -{ - // - // Handle this extension in a way similar to shape. - // - - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; - #endif - - // - // We handle all possible requests of this extension - // using the same opcode. We give to message a data - // offset of 4 (or 16 if proto is >= 3) and handle - // the first 16 bytes through an array of caches. - // - - encodeBuffer.encodeValue(size >> 2, 16, 10); - - encodeBuffer.encodeCachedValue(*(buffer + 1), 8, - clientCache -> shapeOpcodeCache); - - for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) - { - encodeBuffer.encodeCachedValue(GetUINT(buffer + (i * 2) + 4, bigEndian), 16, - *clientCache -> shapeDataCache[i]); - } - - #ifdef DEBUG - *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int ShapeExtensionStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const -{ - ClientCache *clientCache = (ClientCache *) channelCache; - - #ifdef DEBUG - *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; - #endif - - decodeBuffer.decodeValue(size, 16, 10); - - size <<= 2; - - buffer = writeBuffer -> addMessage(size); - - decodeBuffer.decodeCachedValue(*(buffer + 1), 8, - clientCache -> shapeOpcodeCache); - - unsigned int value; - - for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache -> shapeDataCache[i]); - - PutUINT(value, buffer + 4 + (i * 2), bigEndian); - } - - #ifdef DEBUG - *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; - #endif - - return 1; -} - -int ShapeExtensionStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; - - shapeExtension -> opcode = *(buffer + 1); - - for (unsigned int i = 0; i < 8; i++) - { - if ((i * 2 + 4) < size) - { - shapeExtension -> data[i] = GetUINT(buffer + i * 2 + 4, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed data[" << i << "].\n" - << logofs_flush; - #endif - } - else - { - shapeExtension -> data[i] = 0; - } - } - - #ifdef DEBUG - *logofs << name() << ": Parsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int ShapeExtensionStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; - - *(buffer + 1) = shapeExtension -> opcode; - - for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) - { - PutUINT(shapeExtension -> data[i], buffer + i * 2 + 4, bigEndian); - } - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " - << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void ShapeExtensionStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; - - *logofs << name() << ": Identity opcode " << (unsigned) shapeExtension -> opcode; - - for (int i = 0; i < 8; i++) - { - *logofs << ", data[" << i << "] " << shapeExtension -> data[i]; - } - - *logofs << ", size " << shapeExtension -> size_ << ".\n" << logofs_flush; - - #endif -} - -void ShapeExtensionStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - // - // Include minor opcode in the checksum. As data - // offset can be beyond the real end of message, - // we need to include size or we will match any - // message of size less or equal to data offset. - // - - md5_append(md5_state_, buffer + 1, 3); -} - -void ShapeExtensionStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const -{ - // - // Encode the variant part. - // - - ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; - ShapeExtensionMessage *cachedShapeExtension = (ShapeExtensionMessage *) cachedMessage; - - ClientCache *clientCache = (ClientCache *) channelCache; - - for (int i = 0; i < 8 && (i * 2 + 4) < shapeExtension -> size_; i++) - { - #ifdef TEST - *logofs << name() << ": Encoding value " << shapeExtension -> data[i] - << " as data[" << i << "] field.\n" << logofs_flush; - #endif - - encodeBuffer.encodeCachedValue((unsigned int) shapeExtension -> data[i], 16, - *clientCache -> shapeDataCache[i]); - - cachedShapeExtension -> data[i] = shapeExtension -> data[i]; - } -} - -void ShapeExtensionStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const -{ - ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; - - ClientCache *clientCache = (ClientCache *) channelCache; - - unsigned int value; - - for (int i = 0; i < 8 && (i * 2 + 4) < shapeExtension -> size_; i++) - { - decodeBuffer.decodeCachedValue(value, 16, - *clientCache -> shapeDataCache[i]); - - shapeExtension -> data[i] = (unsigned short) value; - - #ifdef TEST - *logofs << name() << ": Decoded value " << shapeExtension -> data[i] - << " as data[" << i << "] field.\n" << logofs_flush; - #endif - } -} diff --git a/nxcomp/ShapeExtension.h b/nxcomp/ShapeExtension.h deleted file mode 100644 index 4dd636847..000000000 --- a/nxcomp/ShapeExtension.h +++ /dev/null @@ -1,164 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef ShapeExtension_H -#define ShapeExtension_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define SHAPEEXTENSION_ENABLE_CACHE 1 -#define SHAPEEXTENSION_ENABLE_DATA 1 -#define SHAPEEXTENSION_ENABLE_SPLIT 0 - -#define SHAPEEXTENSION_DATA_LIMIT 3200 -#define SHAPEEXTENSION_DATA_OFFSET 20 - -#define SHAPEEXTENSION_CACHE_SLOTS 3000 -#define SHAPEEXTENSION_CACHE_THRESHOLD 10 -#define SHAPEEXTENSION_CACHE_LOWER_THRESHOLD 5 - -#define SHAPEEXTENSION_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 - -// -// The message class. -// - -class ShapeExtensionMessage : public Message -{ - friend class ShapeExtensionStore; - - public: - - ShapeExtensionMessage() - { - } - - ~ShapeExtensionMessage() - { - } - - // - // Note for encoding in protocol level 1: we consider - // for this message a data offset of 4. Bytes from 5 - // to 20, if present, are taken as part of identity - // and encoded through an array of int caches. - // - - private: - - unsigned char opcode; - unsigned short data[8]; -}; - -class ShapeExtensionStore : public MessageStore -{ - public: - - ShapeExtensionStore(StaticCompressor *compressor); - - virtual ~ShapeExtensionStore(); - - virtual const char *name() const - { - return "ShapeExtension"; - } - - virtual unsigned char opcode() const - { - return opcode_; - } - - virtual unsigned int storage() const - { - return sizeof(ShapeExtensionMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new ShapeExtensionMessage(); - } - - virtual Message *create(const Message &message) const - { - return new ShapeExtensionMessage((const ShapeExtensionMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (ShapeExtensionMessage *) message; - } - - virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, - const unsigned int size, int bigEndian, - ChannelCache *channelCache) const; - - virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, - unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, - ChannelCache *channelCache) const; - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, - const Message *cachedMessage, - ChannelCache *channelCache) const; - - virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, - ChannelCache *channelCache) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; - - private: - - unsigned char opcode_; -}; - -#endif /* ShapeExtension_H */ diff --git a/nxcomp/Socket.cpp b/nxcomp/Socket.cpp deleted file mode 100644 index 28cb5646d..000000000 --- a/nxcomp/Socket.cpp +++ /dev/null @@ -1,753 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include - -#if defined(__CYGWIN32__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun) -#include -#endif - -#ifdef __sun -#include -#include -#endif - -#include -#include -#include -#include - -#include -#include - -// -// System specific defines. -// - -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun) -#define SOL_IP IPPROTO_IP -#endif - -#ifdef __sun -#define INADDR_NONE ((unsigned int) -1) -#endif - -// -// The TIOCOUTQ ioctl is not implemented on Cygwin. -// Note also that TIOCOUTQ and IPTOS_LOWDELAY are -// disabled when running on MacOS/X. -// - -#ifdef __CYGWIN32__ -#define TIOCOUTQ ((unsigned int) -1) -#endif - -// -// NX includes. -// - -#include "Misc.h" -#include "Socket.h" - -// -// Set verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Set this only once by querying OS details. -// - -static int _kernelStep = -1; - -int GetKernelStep() -{ - if (_kernelStep < 0) - { - // - // At the moment only NX clients run on Win32 - // and MacOS/X so we are not really interested - // in the relevant OS dependent functions. - // - - #if defined(__CYGWIN32__) || defined(__APPLE__) - - _kernelStep = 0; - - #else - - struct utsname buffer; - - if (uname(&buffer) < 0) - { - #ifdef WARNING - *logofs << "Socket: WARNING! Failed to get system info. Error is " - << EGET() << " '" << ESTR() << "'.\n" << logofs_flush; - - *logofs << "Socket: WARNING! Assuming lowest system support.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Failed to get system info. Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - cerr << "Warning" << ": Assuming lowest system support.\n"; - - _kernelStep = 0; - } - else - { - #ifdef TEST - *logofs << "Socket: System is '" << buffer.sysname - << "' nodename '" << buffer.nodename << "' release '" - << buffer.release << "'.\n" << logofs_flush; - - *logofs << "Socket: Version is '" << buffer.version << "' machine '" - << buffer.machine << "'.\n" << logofs_flush; - #endif - - // - // Should test support on other operating systems. - // - - if (strcmp(buffer.sysname, "Linux") == 0) - { - if (strncmp(buffer.release, "2.0.", 4) == 0 || - strncmp(buffer.release, "2.2.", 4) == 0) - { - #ifdef TEST - *logofs << "Socket: Assuming level 2 system support.\n" - << logofs_flush; - #endif - - _kernelStep = 2; - } - else - { - #ifdef TEST - *logofs << "Socket: Assuming level 3 system support.\n" - << logofs_flush; - #endif - - _kernelStep = 3; - } - } - else if (strcmp(buffer.sysname, "SunOS") == 0) - { - #ifdef TEST - *logofs << "Socket: Assuming level 1 system support.\n" - << logofs_flush; - #endif - - _kernelStep = 1; - } - else - { - #ifdef TEST - *logofs << "Socket: Assuming level 0 system support.\n" - << logofs_flush; - #endif - - _kernelStep = 0; - } - } - - #endif /* #if defined(__CYGWIN32__) || defined(__APPLE__) */ - } - - return _kernelStep; -} - -int SetReuseAddress(int fd) -{ - int flag = 1; - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (char *) &flag, sizeof(flag)) < 0) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to set SO_REUSEADDR flag on FD#" - << fd << ". Error is " << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed to set SO_REUSEADDR flag on FD#" - << fd << ". Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - return -1; - } - #ifdef TEST - else - { - *logofs << "Socket: Set SO_REUSEADDR flag on FD#" - << fd << ".\n" << logofs_flush; - } - #endif - - return 1; -} - -int SetNonBlocking(int fd, int value) -{ - int flags = fcntl(fd, F_GETFL); - - if (flags >= 0) - { - if (value == 0) - { - flags &= ~O_NONBLOCK; - } - else - { - flags |= O_NONBLOCK; - } - } - - if (flags < 0 || fcntl(fd, F_SETFL, flags) < 0) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to set O_NONBLOCK flag on FD#" - << fd << " to " << value << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to set O_NONBLOCK flag on FD#" - << fd << " to " << value << ". Error is " << EGET() - << " '" << ESTR() << "'.\n"; - - return -1; - } - #ifdef TEST - else - { - *logofs << "Socket: Set O_NONBLOCK flag on FD#" - << fd << " to " << value << ".\n" - << logofs_flush; - } - #endif - - return 1; -} - -int SetLingerTimeout(int fd, int timeout) -{ - struct linger linger_value; - - if (timeout > 0) - { - linger_value.l_onoff = 1; - linger_value.l_linger = timeout; - } - else - { - linger_value.l_onoff = 0; - linger_value.l_linger = 0; - } - - if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger_value, sizeof(linger_value)) < 0) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to set SO_LINGER values to " - << linger_value.l_onoff << " and " << linger_value.l_linger - << " on FD#" << fd << ". Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to set SO_LINGER values to " - << linger_value.l_onoff << " and " << linger_value.l_linger - << " on FD#" << fd << ". Error is " << EGET() << " '" - << ESTR() << "'.\n"; - - return -1; - } - #ifdef TEST - else - { - *logofs << "Socket: Set SO_LINGER values to " - << linger_value.l_onoff << " and " << linger_value.l_linger - << " on FD#" << fd << ".\n" << logofs_flush; - } - #endif - - return 1; -} - -int SetSendBuffer(int fd, int size) -{ - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to set SO_SNDBUF size to " - << size << " on FD#" << fd << ". Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed to set SO_SNDBUF size to " - << size << " on FD#" << fd << ". Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - return -1; - } - #ifdef TEST - else - { - *logofs << "Socket: Set SO_SNDBUF on FD#" << fd - << " to " << size << " bytes.\n" - << logofs_flush; - } - #endif - - return 1; -} - -int SetReceiveBuffer(int fd, int size) -{ - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to set SO_RCVBUF size to " - << size << " on FD#" << fd << ". Error is " - << EGET() << " '" << ESTR() << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed to set SO_RCVBUF size to " - << size << " on FD#" << fd << ". Error is " - << EGET() << " '" << ESTR() << "'.\n"; - - return -1; - } - #ifdef TEST - else - { - *logofs << "Socket: Set SO_RCVBUF on FD#" << fd - << " to " << size << " bytes.\n" - << logofs_flush; - } - #endif - - return 1; -} - -int SetNoDelay(int fd, int value) -{ - int result = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)); - - if (result == 0) - { - result = 1; - } - else if (result < 0) - { - // - // Is it become a different error on - // Mac OSX 10.4? - // - - #if defined(__APPLE__) - - result = 0; - - #endif - - #if defined(__sun) - - if (EGET() == ENOPROTOOPT) - { - result = 0; - } - - #endif - - #if !defined(__APPLE__) && !defined(__sun) - - if (EGET() == EOPNOTSUPP) - { - result = 0; - } - - #endif - } - - if (result < 0) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to set TCP_NODELAY flag on " - << "FD#" << fd << " to " << value << ". Error is " - << EGET() << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to set TCP_NODELAY flag on " - << "FD#" << fd << " to " << value << ". Error is " - << EGET() << " '" << ESTR() << "'.\n"; - } - #ifdef TEST - else if (result == 0) - { - #ifdef TEST - *logofs << "Socket: Option TCP_NODELAY not supported " - << "on FD#" << fd << ".\n" << logofs_flush; - #endif - } - else - { - *logofs << "Socket: Set TCP_NODELAY flag on FD#" - << fd << " to " << value << ".\n" - << logofs_flush; - } - #endif - - return result; -} - -int SetKeepAlive(int fd) -{ - int flag = 1; - - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag)) < 0) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to set SO_KEEPALIVE flag on " - << "FD#" << fd << ". Error is " << EGET() << " '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to set SO_KEEPALIVE flag on " - << "FD#" << fd << ". Error is " << EGET() << " '" - << ESTR() << "'.\n"; - - return -1; - } - #ifdef TEST - else - { - *logofs << "Socket: Set SO_KEEPALIVE flag on FD#" - << fd << ".\n" << logofs_flush; - } - #endif - - return 1; -} - -int SetLowDelay(int fd) -{ - if (_kernelStep < 0) - { - GetKernelStep(); - } - - switch (_kernelStep) - { - case 3: - case 2: - case 1: - { - int flag = IPTOS_LOWDELAY; - - if (setsockopt(fd, SOL_IP, IP_TOS, &flag, sizeof(flag)) < 0) - { - if (EGET() == EOPNOTSUPP) - { - #ifdef TEST - *logofs << "Socket: Option IPTOS_LOWDELAY not supported " - << "on FD#" << fd << ".\n" << logofs_flush; - #endif - - return 0; - } - else - { - #ifdef WARNING - *logofs << "Socket: WARNING! Failed to set IPTOS_LOWDELAY flag on " - << "FD#" << fd << ". Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Failed to set IPTOS_LOWDELAY flag on " - << "FD#" << fd << ". Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - return -1; - } - } - #ifdef TEST - else - { - *logofs << "Socket: Set IPTOS_LOWDELAY flag on FD#" - << fd << ".\n" << logofs_flush; - } - #endif - - return 1; - } - default: - { - #ifdef TEST - *logofs << "Socket: Option IPTOS_LOWDELAY not " - << "supported on FD#" << fd << ".\n" - << logofs_flush; - #endif - - return 0; - } - } -} - -int SetCloseOnExec(int fd) -{ - if (fcntl(fd, F_SETFD, 1) != 0) - { - #ifdef TEST - *logofs << "NXClient: PANIC! Cannot set close-on-exec " - << "on FD#" << fd << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot set close-on-exec on FD#" - << fd << ". Error is " << EGET() << " '" << ESTR() - << "'.\n"; - - return -1; - } - - return 1; -} - -int GetBytesReadable(int fd) -{ - long readable = 0; - - // - // It may fail, for example at session - // shutdown. - // - - if (ioctl(fd, FIONREAD, &readable) < 0) - { - #ifdef TEST - *logofs << "Socket: PANIC! Failed to get bytes readable " - << "from FD#" << fd << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - return -1; - } - - #ifdef TEST - *logofs << "Socket: Returning " << (int) readable - << " bytes readable on FD#" << fd << ".\n" - << logofs_flush; - #endif - - return (int) readable; -} - -int GetBytesWritable(int fd) -{ - if (_kernelStep < 0) - { - GetKernelStep(); - } - - long writable; - - switch (_kernelStep) - { - case 3: - { - // - // TODO: Should query the real size - // of the TCP write buffer. - // - - writable = 16384 - GetBytesQueued(fd); - - if (writable < 0) - { - writable = 0; - } - - break; - } - case 2: - { - if (ioctl(fd, TIOCOUTQ, (void *) &writable) < 0) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to get bytes writable " - << "on FD#" << fd << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to get bytes writable " - << "on FD#" << fd << ". Error is " << EGET() - << " '" << ESTR() << "'.\n"; - - return -1; - } - - break; - } - default: - { - #ifdef TEST - *logofs << "Socket: Option TIOCOUTQ not supported " - << "on FD#" << fd << ",\n" << logofs_flush; - #endif - - // - // TODO: Should query the real size - // of the TCP write buffer. - // - - writable = 16384; - - break; - } - } - - #ifdef TEST - *logofs << "Socket: Returning " << writable - << " bytes writable on FD#" << fd - << ".\n" << logofs_flush; - #endif - - return (int) writable; -} - -int GetBytesQueued(int fd) -{ - // - // The TIOCOUTQ ioctl is not implemented on Cygwin - // and returns the space available on Linux Kernels - // 2.0 and 2.2 (like current MIPS for PS/2). - // - - if (_kernelStep < 0) - { - GetKernelStep(); - } - - long queued; - - switch (_kernelStep) - { - case 3: - { - if (ioctl(fd, TIOCOUTQ, (void *) &queued) < 0) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to get bytes queued " - << "on FD#" << fd << ". Error is " << EGET() - << " '" << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to get bytes queued " - << "on FD#" << fd << ". Error is " << EGET() - << " '" << ESTR() << "'.\n"; - - return -1; - } - - break; - } - case 2: - { - // - // TODO: Should query the real size - // of the TCP write buffer. - // - - queued = 16384 - GetBytesWritable(fd); - - if (queued < 0) - { - queued = 0; - } - - break; - } - default: - { - #ifdef TEST - *logofs << "Socket: Option TIOCOUTQ not supported " - << "on FD#" << fd << ",\n" << logofs_flush; - #endif - - queued = 0; - - break; - } - } - - #ifdef TEST - *logofs << "Socket: Returning " << queued - << " bytes queued on FD#" << fd - << ".\n" << logofs_flush; - #endif - - return (int) queued; -} - -int GetHostAddress(const char *name) -{ - hostent *host = gethostbyname(name); - - if (host == NULL) - { - // - // On some Unices gethostbyname() doesn't - // accept IP addresses, so try inet_addr. - // - - IN_ADDR_T address = inet_addr(name); - - if (address == INADDR_NONE) - { - #ifdef PANIC - *logofs << "Socket: PANIC! Failed to resolve address of '" - << name << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed to resolve address of '" - << name << "'.\n"; - - return 0; - } - - return (int) address; - } - else - { - return (*((int *) host -> h_addr_list[0])); - } -} diff --git a/nxcomp/Socket.h b/nxcomp/Socket.h deleted file mode 100644 index 5e7e47705..000000000 --- a/nxcomp/Socket.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Socket_H -#define Socket_H - -#include -#include -#include - -#ifdef __sun -#include -#include -#endif - -// -// Set socket options. -// - -int SetReuseAddress(int fd); -int SetNonBlocking(int fd, int value); -int SetLingerTimeout(int fd, int timeout); -int SetSendBuffer(int fd, int size); -int SetReceiveBuffer(int fd, int size); -int SetNoDelay(int fd, int value); -int SetKeepAlive(int fd); -int SetLowDelay(int fd); -int SetCloseOnExec(int fd); - -// -// Get kernel support level. -// - -int GetKernelStep(); - -// -// Get socket info. -// - -int GetBytesReadable(int fd); -int GetBytesWritable(int fd); -int GetBytesQueued(int fd); - -// -// Inline version, providing direct access -// to the interface. -// - -#include "Misc.h" - -inline int GetBytesReadable(int fd, int *readable) -{ - long t; - - int result = ioctl(fd, FIONREAD, &t); - - #ifdef DEBUG - *logofs << "Socket: Bytes readable from FD#" - << fd << " are " << t << " with result " - << result << ".\n" << logofs_flush; - #endif - - *readable = (int) t; - - return result; -} - -// -// Query Internet address. -// - -int GetHostAddress(const char *name); - -#endif /* Socket_H */ diff --git a/nxcomp/Split.cpp b/nxcomp/Split.cpp deleted file mode 100644 index b6828c7cb..000000000 --- a/nxcomp/Split.cpp +++ /dev/null @@ -1,1835 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include -#include - -#include "Misc.h" - -#include "Split.h" - -#include "Control.h" -#include "Statistics.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "StaticCompressor.h" - -#include "Unpack.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Define this to trace elements -// allocated and deallocated. -// - -#undef REFERENCES - -// -// Counters used for store control. -// - -int SplitStore::totalSplitSize_; -int SplitStore::totalSplitStorageSize_; - -// -// This is used for reference count. -// - -#ifdef REFERENCES - -int Split::references_ = 0; - -#endif - -Split::Split() -{ - resource_ = nothing; - position_ = nothing; - - store_ = NULL; - - d_size_ = 0; - i_size_ = 0; - c_size_ = 0; - r_size_ = 0; - - next_ = 0; - load_ = 0; - save_ = 0; - - checksum_ = NULL; - state_ = split_undefined; - mode_ = split_none; - action_ = is_discarded; - - #ifdef REFERENCES - - references_++; - - *logofs << "Split: Created new Split at " - << this << " out of " << references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -Split::~Split() -{ - delete [] checksum_; - - #ifdef REFERENCES - - references_--; - - *logofs << "Split: Deleted Split at " - << this << " out of " << references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -SplitStore::SplitStore(StaticCompressor *compressor, CommitStore *commits, int resource) - - : compressor_(compressor), commits_(commits), resource_(resource) -{ - splits_ = new T_splits(); - - current_ = splits_ -> end(); - - splitStorageSize_ = 0; - - #ifdef TEST - *logofs << "SplitStore: Created new store ["; - - if (resource_ != nothing) - { - *logofs << resource_; - } - else - { - *logofs << "commit"; - } - - *logofs << "].\n" << logofs_flush; - - *logofs << "SplitStore: Total messages in stores are " - << totalSplitSize_ << " with total storage size " - << totalSplitStorageSize_ << ".\n" - << logofs_flush; - #endif -} - -SplitStore::~SplitStore() -{ - totalSplitSize_ -= splits_ -> size(); - - totalSplitStorageSize_ -= splitStorageSize_; - - for (T_splits::iterator i = splits_ -> begin(); - i != splits_ -> end(); i++) - { - delete *i; - } - - delete splits_; - - #ifdef TEST - *logofs << "SplitStore: Deleted store ["; - - if (resource_ != nothing) - { - *logofs << resource_; - } - else - { - *logofs << "commit"; - } - - *logofs << "] with storage size " << splitStorageSize_ - << ".\n" << logofs_flush; - - *logofs << "SplitStore: Total messages in stores are " - << totalSplitSize_ << " with total storage size " - << totalSplitStorageSize_ << ".\n" - << logofs_flush; - #endif -} - -// -// This is called at the encoding side. -// - -Split *SplitStore::add(MessageStore *store, int resource, T_split_mode mode, - int position, T_store_action action, T_checksum checksum, - const unsigned char *buffer, const int size) -{ - #ifdef TEST - *logofs << "SplitStore: Adding message [" << (unsigned int) store -> - opcode() << "] resource " << resource << " mode " << mode - << " position " << position << " action [" << DumpAction(action) - << "] and checksum [" << DumpChecksum(checksum) << "]" - << ".\n" << logofs_flush; - #endif - - Split *split = new Split(); - - if (split == NULL) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Can't allocate " - << "memory for the split.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the split.\n"; - - HandleAbort(); - } - - split -> store_ = store; - split -> resource_ = resource; - split -> mode_ = mode; - split -> position_ = position; - split -> action_ = action; - - split -> store_ -> validateSize(size); - - // - // The checksum is not provided if the - // message is cached. - // - - if (checksum != NULL) - { - split -> checksum_ = new md5_byte_t[MD5_LENGTH]; - - memcpy(split -> checksum_, checksum, MD5_LENGTH); - } - - // - // We don't need the identity data at the - // encoding side. This qualifies the split - // as a split generated at the encoding - // side. - // - - split -> i_size_ = store -> identitySize(buffer, size); - - split -> d_size_ = size - split -> i_size_; - - if (action == IS_ADDED || action == is_discarded) - { - // - // If the message was added to message - // store or discarded we need to save - // the real data so we can transfer it - // at later time. - // - - split -> data_.resize(split -> d_size_); - - memcpy(split -> data_.begin(), buffer + split -> i_size_, split -> d_size_); - - // - // If the message was added, lock it so - // it will not be used by the encoding - // side until it is recomposed. - // - - if (action == IS_ADDED) - { - split -> store_ -> lock(split -> position_); - - #ifdef TEST - - commits_ -> validate(split); - - #endif - } - } - #ifdef WARNING - else - { - *logofs << "SplitStore: WARNING! Not copying data for the cached message.\n" - << logofs_flush; - } - #endif - - push(split); - - return split; -} - -// -// This is called at decoding side. If checksum -// is provided, the message can be searched on -// disk, then, if message is found, an event is -// sent to abort the data transfer. -// - -Split *SplitStore::add(MessageStore *store, int resource, int position, - T_store_action action, T_checksum checksum, - unsigned char *buffer, const int size) -{ - #ifdef TEST - *logofs << "SplitStore: Adding message [" - << (unsigned int) store -> opcode() << "] resource " - << resource << " position " << position << " action [" - << DumpAction(action) << "] and checksum [" - << DumpChecksum(checksum) << "].\n" << logofs_flush; - #endif - - Split *split = new Split(); - - if (split == NULL) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Can't allocate " - << "memory for the split.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory " - << "for the split.\n"; - - HandleAbort(); - } - - split -> store_ = store; - split -> resource_ = resource; - split -> position_ = position; - split -> action_ = action; - - split -> store_ -> validateSize(size); - - // - // Check if the checksum was provided - // by the remote. - // - - if (checksum != NULL) - { - split -> checksum_ = new md5_byte_t[MD5_LENGTH]; - - memcpy(split -> checksum_, checksum, MD5_LENGTH); - } - - split -> i_size_ = store -> identitySize(buffer, size); - - // - // Copy the identity so we can expand the - // message when it is committed. - // - - split -> identity_.resize(split -> i_size_); - - memcpy(split -> identity_.begin(), buffer, split -> i_size_); - - split -> d_size_ = size - split -> i_size_; - - if (action == IS_ADDED || action == is_discarded) - { - // - // The unpack procedure will check if the - // first 2 bytes of the buffer contain the - // pattern and will not try to expand the - // image. - // - - split -> data_.resize(2); - - unsigned char *data = split -> data_.begin(); - - data[0] = SPLIT_PATTERN; - data[1] = SPLIT_PATTERN; - - // - // If the message was added to the store, - // we don't have the data part, yet, so - // we need to lock the message until it - // is recomposed. - // - - if (action == IS_ADDED) - { - split -> store_ -> lock(split -> position_); - - #ifdef TEST - - commits_ -> validate(split); - - #endif - } - } - else - { - #ifdef WARNING - *logofs << "SplitStore: WARNING! Copying data for the cached message.\n" - << logofs_flush; - #endif - - // - // We may optionally take the data from the - // message store in compressed form, but, - // as the data has been decompressed in the - // buffer, we save a further decompression. - // - - split -> data_.resize(split -> d_size_); - - memcpy(split -> data_.begin(), buffer + split -> i_size_, split -> d_size_); - } - - push(split); - - return split; -} - -void SplitStore::push(Split *split) -{ - splits_ -> push_back(split); - - splitStorageSize_ += getNodeSize(split); - - totalSplitSize_++; - - totalSplitStorageSize_ += getNodeSize(split); - - statistics -> addSplit(); - - #ifdef TEST - *logofs << "SplitStore: There are " << splits_ -> size() - << " messages in store [" << resource_ << "] with " - << "storage size " << splitStorageSize_ << ".\n" - << logofs_flush; - - *logofs << "SplitStore: Total messages in stores are " - << totalSplitSize_ << " with total storage size " - << totalSplitStorageSize_ << ".\n" - << logofs_flush; - #endif - - split -> state_ = split_added; -} - -void SplitStore::dump() -{ - #ifdef DUMP - - int n; - - Split *split; - - *logofs << "SplitStore: DUMP! Dumping content of "; - - if (commits_ == NULL) - { - *logofs << "[commits]"; - } - else - { - *logofs << "[splits] for store [" << resource_ << "]"; - } - - *logofs << " with [" << getSize() << "] elements " - << "in the store.\n" << logofs_flush; - - n = 0; - - for (T_splits::iterator i = splits_ -> begin(); i != splits_ -> end(); i++, n++) - { - split = *i; - - *logofs << "SplitStore: DUMP! Split [" << n << "] has action [" - << DumpAction(split -> action_) << "] state [" - << DumpState(split -> state_) << "] "; - - if (split -> resource_ >= 0) - { - *logofs << "resource " << split -> resource_; - } - - *logofs << " request " << (unsigned) split -> store_ -> opcode() - << " position " << split -> position_ << " size is " - << split -> data_.size() << " (" << split -> d_size_ - << "/" << split -> c_size_ << "/" << split -> r_size_ - << ") with " << split -> data_.size() - split -> next_ - << "] bytes to go.\n" << logofs_flush; - } - - #endif -} - -int SplitStore::send(EncodeBuffer &encodeBuffer, int packetSize) -{ - if (splits_ -> size() == 0) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Function send called with no splits available.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Function send called with no splits available.\n"; - - HandleAbort(); - } - - // - // A start operation must always be executed on - // the split, even in the case the split will be - // later aborted. - // - - if (current_ == splits_ -> end()) - { - start(encodeBuffer); - } - - // - // If we have matched the checksum received from - // the remote side then we must abort the current - // split, else we can send another block of data - // to the remote peer. - // - - Split *split = *current_; - - unsigned int abort = 0; - - if (split -> state_ == split_loaded) - { - abort = 1; - } - - encodeBuffer.encodeBoolValue(abort); - - if (abort == 1) - { - #ifdef TEST - *logofs << "SplitStore: Aborting split for checksum [" - << DumpChecksum(split -> checksum_) << "] position " - << split -> position_ << " with " << (split -> - data_.size() - split -> next_) << " bytes to go " - << "out of " << split -> data_.size() - << ".\n" << logofs_flush; - #endif - - statistics -> addSplitAborted(); - - statistics -> addSplitAbortedBytesOut(split -> data_.size() - split -> next_); - - split -> next_ = split -> data_.size(); - - split -> state_ = split_aborted; - } - else - { - int count = (packetSize <= 0 || split -> next_ + - packetSize > (int) split -> data_.size() ? - split -> data_.size() - split -> next_ : packetSize); - - #ifdef TEST - *logofs << "SplitStore: Sending split for checksum [" - << DumpChecksum(split -> checksum_) << "] count " - << count << " position " << split -> position_ - << ". Data size is " << split -> data_.size() << " (" - << split -> d_size_ << "/" << split -> c_size_ << "), " - << split -> data_.size() - (split -> next_ + count) - << " to go.\n" << logofs_flush; - #endif - - encodeBuffer.encodeValue(count, 32, 10); - - encodeBuffer.encodeMemory(split -> data_.begin() + split -> next_, count); - - split -> next_ += count; - } - - // - // Was data completely transferred? We are the - // sending side. We must update the message in - // store, even if split was aborted. - // - - if (split -> next_ != ((int) split -> data_.size())) - { - return 0; - } - - // - // Move the split at the head of the - // list to the commits. - // - - remove(split); - - // - // Reset current position to the - // end of repository. - // - - current_ = splits_ -> end(); - - #ifdef TEST - *logofs << "SplitStore: Removed split at head of the list. " - << "Resource is " << split -> resource_ << " request " - << (unsigned) split -> store_ -> opcode() << " position " - << split -> position_ << ".\n" << logofs_flush; - #endif - - return 1; -} - -int SplitStore::start(EncodeBuffer &encodeBuffer) -{ - // - // Get the element at the top of the - // list. - // - - current_ = splits_ -> begin(); - - Split *split = *current_; - - #ifdef TEST - *logofs << "SplitStore: Starting split for checksum [" - << DumpChecksum(split -> checksum_) << "] position " - << split -> position_ << " with " << (split -> - data_.size() - split -> next_) << " bytes to go " - << "out of " << split -> data_.size() - << ".\n" << logofs_flush; - #endif - - // - // See if compression of the data part is - // enabled. - // - - if (split -> store_ -> enableCompress) - { - // - // If the split is going to be aborted don't - // compress the data and go straight to the - // send. The new data size will be assumed - // from the disk cache. - // - - if (split -> state_ != split_loaded) - { - unsigned int compressedSize = 0; - unsigned char *compressedData = NULL; - - if (control -> LocalDataCompression && - (compressor_ -> compressBuffer(split -> data_.begin(), split -> d_size_, - compressedData, compressedSize))) - { - // - // Replace the data with the one in - // compressed form. - // - - #ifdef TEST - *logofs << "SplitStore: Split data of size " << split -> d_size_ - << " has been compressed to " << compressedSize - << " bytes.\n" << logofs_flush; - #endif - - split -> data_.clear(); - - split -> data_.resize(compressedSize); - - memcpy(split -> data_.begin(), compressedData, compressedSize); - - split -> c_size_ = compressedSize; - - // - // Inform our peer that the data is - // compressed and send the new size. - // - - encodeBuffer.encodeBoolValue(1); - - encodeBuffer.encodeValue(compressedSize, 32, 14); - - #ifdef TEST - *logofs << "SplitStore: Signaled " << split -> c_size_ - << " bytes of compressed data for this message.\n" - << logofs_flush; - #endif - - return 1; - } - } - #ifdef TEST - else - { - *logofs << "SplitStore: Not trying to compress the " - << "loaded message.\n" << logofs_flush; - } - #endif - - // - // Tell to the remote that data will - // follow uncompressed. - // - - encodeBuffer.encodeBoolValue(0); - } - - return 1; -} - -int SplitStore::start(DecodeBuffer &decodeBuffer) -{ - #ifdef TEST - *logofs << "SplitStore: Going to receive a new split from the remote side.\n" - << logofs_flush; - #endif - - // - // Get the element at the head - // of the list. - // - - current_ = splits_ -> begin(); - - Split *split = *current_; - - unsigned int compressedSize = 0; - - // - // Save the data size known by the remote. - // This information will be needed if the - // remote will not have a chance to abort - // the split. - // - - split -> r_size_ = split -> d_size_; - - // - // Find out if data was compressed by the - // remote. - // - - if (split -> store_ -> enableCompress) - { - decodeBuffer.decodeBoolValue(compressedSize); - - if (compressedSize == 1) - { - // - // Get the compressed size. - // - - // Since ProtoStep7 (#issue 108) - decodeBuffer.decodeValue(compressedSize, 32, 14); - - split -> store_ -> validateSize(split -> d_size_, compressedSize); - - split -> r_size_ = compressedSize; - } - } - - // - // Update the size if the split - // was not already loaded. - // - - if (split -> state_ != split_loaded) - { - split -> data_.clear(); - - if (compressedSize > 0) - { - split -> c_size_ = compressedSize; - - #ifdef TEST - *logofs << "SplitStore: Split data of size " - << split -> d_size_ << " was compressed to " - << split -> c_size_ << " bytes.\n" - << logofs_flush; - #endif - - split -> data_.resize(split -> c_size_); - } - else - { - split -> data_.resize(split -> d_size_); - } - - unsigned char *data = split -> data_.begin(); - - data[0] = SPLIT_PATTERN; - data[1] = SPLIT_PATTERN; - } - #ifdef TEST - else - { - // - // The message had been already - // loaded from disk. - // - - if (compressedSize > 0) - { - if ((int) compressedSize != split -> c_size_) - { - *logofs << "SplitStore: WARNING! Compressed data size is " - << "different than the loaded compressed size.\n" - << logofs_flush; - } - - *logofs << "SplitStore: Ignoring the new size with " - << "loaded compressed size " << split -> c_size_ - << ".\n" << logofs_flush; - } - } - #endif - - return 1; -} - -int SplitStore::receive(DecodeBuffer &decodeBuffer) -{ - if (splits_ -> size() == 0) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Function receive called with no splits available.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Function receive called with no splits available.\n"; - - HandleAbort(); - } - - if (current_ == splits_ -> end()) - { - start(decodeBuffer); - } - - // - // Check first if split was aborted, else add - // any new data to message being recomposed. - // - - Split *split = *current_; - - unsigned int abort = 0; - - decodeBuffer.decodeBoolValue(abort); - - if (abort == 1) - { - #ifdef TEST - *logofs << "SplitStore: Aborting split for checksum [" - << DumpChecksum(split -> checksum_) << "] position " - << split -> position_ << " with " << (split -> - data_.size() - split -> next_) << " bytes to go " - << "out of " << split -> data_.size() - << ".\n" << logofs_flush; - #endif - - statistics -> addSplitAborted(); - - statistics -> addSplitAbortedBytesOut(split -> r_size_ - split -> next_); - - split -> next_ = split -> r_size_; - - split -> state_ = split_aborted; - } - else - { - // - // Get the size of the packet. - // - - unsigned int count; - - decodeBuffer.decodeValue(count, 32, 10); - - // - // If the split was not already loaded from - // disk, decode the packet and update our - // copy of the data. The encoding side may - // have not received the abort event, yet, - // and may be unaware that the message is - // stored in compressed form at our side. - // - - #ifdef TEST - *logofs << "SplitStore: Receiving split for checksum [" - << DumpChecksum(split -> checksum_) << "] count " - << count << " position " << split -> position_ - << ". Data size is " << split -> data_.size() << " (" - << split -> d_size_ << "/" << split -> c_size_ << "/" - << split -> r_size_ << "), " << split -> r_size_ - - (split -> next_ + count) << " to go.\n" - << logofs_flush; - #endif - - if (split -> next_ + count > (unsigned) split -> r_size_) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Invalid data count " - << count << "provided in the split.\n" - << logofs_flush; - - *logofs << "SplitStore: PANIC! While receiving split for " - << "checksum [" << DumpChecksum(split -> checksum_) - << "] with count " << count << " action [" - << DumpAction(split -> action_) << "] state [" - << DumpState(split -> state_) << "]. Data size is " - << split -> data_.size() << " (" << split -> d_size_ - << "/" << split -> c_size_ << "), " << split -> - data_.size() - (split -> next_ + count) - << " to go.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Invalid data count " - << count << "provided in the split.\n"; - - HandleAbort(); - } - - if (split -> state_ != split_loaded) - { - #ifdef TEST - - if (split -> next_ + count > split -> data_.size()) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Inconsistent split data size " - << split -> data_.size() << " with expected size " - << split -> r_size_ << ".\n" - << logofs_flush; - #endif - - HandleAbort(); - } - - #endif - - memcpy(split -> data_.begin() + split -> next_, - decodeBuffer.decodeMemory(count), count); - } - else - { - #ifdef TEST - *logofs << "SplitStore: WARNING! Data discarded with split " - << "loaded from disk.\n" << logofs_flush; - #endif - - decodeBuffer.decodeMemory(count); - } - - split -> next_ += count; - } - - // - // Is unsplit complete? - // - - if (split -> next_ != split -> r_size_) - { - return 0; - } - - // - // If the persistent cache is enabled, - // we have a valid checksum and the - // split was not originally retrieved - // from disk, save the message on disk. - // - - if (split -> state_ != split_loaded && - split -> state_ != split_aborted) - { - save(split); - } - - // - // Move the split at the head of the - // list to the commits. - // - - remove(split); - - // - // Reset the current position to the - // end of the repository. - // - - current_ = splits_ -> end(); - - #ifdef TEST - *logofs << "SplitStore: Removed split at head of the list. " - << "Resource is " << split -> resource_ << " request " - << (unsigned) split -> store_ -> opcode() << " position " - << split -> position_ << ".\n" << logofs_flush; - #endif - - return 1; -} - -Split *SplitStore::pop() -{ - if (splits_ -> size() == 0) - { - #ifdef TEST - *logofs << "SplitStore: The split store is empty.\n" - << logofs_flush; - #endif - - return NULL; - } - - // - // Move the pointer at the end of the list. - // The next send operation will eventually - // start a new split. - // - - current_ = splits_ -> end(); - - Split *split = *(splits_ -> begin()); - - splits_ -> pop_front(); - - #ifdef TEST - *logofs << "SplitStore: Removed split at the head of the " - << "list with resource " << split -> resource_ - << " request " << (unsigned) split -> store_ -> - opcode() << " position " << split -> position_ - << ".\n" << logofs_flush; - #endif - - splitStorageSize_ -= getNodeSize(split); - - totalSplitSize_--; - - totalSplitStorageSize_ -= getNodeSize(split); - - #ifdef TEST - *logofs << "SplitStore: There are " << splits_ -> size() - << " messages in store [" << resource_ << "] with " - << "storage size " << splitStorageSize_ << ".\n" - << logofs_flush; - - *logofs << "SplitStore: Total messages in stores are " - << totalSplitSize_ << " with total storage size " - << totalSplitStorageSize_ << ".\n" - << logofs_flush; - #endif - - return split; -} - -void SplitStore::remove(Split *split) -{ - #ifdef TEST - *logofs << "SplitStore: Going to remove the split from the list.\n" - << logofs_flush; - #endif - - #ifdef TEST - - if (split != getFirstSplit()) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Trying to remove a split " - << "not at the head of the list.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Trying to remove a split " - << "not at the head of the list.\n"; - - HandleAbort(); - } - - #endif - - // - // Move the split to the commit store. - // - - splits_ -> pop_front(); - - commits_ -> splits_ -> push_back(split); - - splitStorageSize_ -= getNodeSize(split); - - totalSplitSize_--; - - totalSplitStorageSize_ -= getNodeSize(split); - - #ifdef TEST - *logofs << "SplitStore: There are " << splits_ -> size() - << " messages in store [" << resource_ << "] with " - << "storage size " << splitStorageSize_ << ".\n" - << logofs_flush; - - *logofs << "SplitStore: Total messages in stores are " - << totalSplitSize_ << " with total storage size " - << totalSplitStorageSize_ << ".\n" - << logofs_flush; - #endif - - #ifdef TEST - - if (splits_ -> size() == 0) - { - if (splitStorageSize_ != 0) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Internal error calculating " - << "split data size. It is " << splitStorageSize_ - << " while should be 0.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Internal error calculating " - << "split data size. It is " << splitStorageSize_ - << " while should be 0.\n"; - - HandleAbort(); - } - } - - #endif -} - -const char *SplitStore::name(const T_checksum checksum) -{ - if (checksum == NULL) - { - return NULL; - } - - char *pathName = control -> ImageCachePath; - - if (pathName == NULL) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Cannot determine directory of " - << "NX image files.\n" << logofs_flush; - #endif - - return NULL; - } - - int pathSize = strlen(pathName); - - // - // File name is "[path][/I-c/I-][checksum][\0]", - // where c is the first hex digit of checksum. - // - - int nameSize = pathSize + 7 + MD5_LENGTH * 2 + 1; - - char *fileName = new char[nameSize]; - - if (fileName == NULL) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Cannot allocate space for " - << "NX image file name.\n" << logofs_flush; - #endif - - return NULL; - } - - strcpy(fileName, pathName); - - sprintf(fileName + pathSize, "/I-%1X/I-", - *((unsigned char *) checksum) >> 4); - - for (unsigned int i = 0; i < MD5_LENGTH; i++) - { - sprintf(fileName + pathSize + 7 + (i * 2), "%02X", - ((unsigned char *) checksum)[i]); - } - - return fileName; -} - -int SplitStore::save(Split *split) -{ - // - // Check if saving the message on the - // persistent cache is enabled. - // - - if (split -> save_ == 0) - { - return 0; - } - - T_checksum checksum = split -> checksum_; - - const char *fileName = name(checksum); - - if (fileName == NULL) - { - return 0; - } - - unsigned int splitSize; - - ostream *fileStream = NULL; - - unsigned char *fileHeader = NULL; - - // - // Get the other data from the split. - // - - unsigned char opcode = split -> store_ -> opcode(); - - unsigned char *data = split -> data_.begin(); - - int dataSize = split -> d_size_; - int compressedSize = split -> c_size_; - - #ifdef DEBUG - *logofs << "SplitStore: Going to save split OPCODE#" - << (unsigned int) opcode << " to file '" << fileName - << "' with size " << dataSize << " and compressed size " - << compressedSize << ".\n" << logofs_flush; - #endif - - DisableSignals(); - - // - // Change the mask to make the file only - // readable by the user, then restore the - // old mask. - // - - mode_t fileMode; - - // - // Check if the file already exists. We try to - // load the message when the split is started - // and save it only if it is not found. Still - // the remote side may send the same image mul- - // tiple time and we may not have the time to - // notify the abort. - // - - struct stat fileStat; - - if (stat(fileName, &fileStat) == 0) - { - #ifdef TEST - *logofs << "SplitStore: Image file '" << fileName - << "' already present on disk.\n" - << logofs_flush; - #endif - - goto SplitStoreSaveError; - } - - fileMode = umask(0077); - - fileStream = new ofstream(fileName, ios::out | ios::binary); - - umask(fileMode); - - if (CheckData(fileStream) < 0) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Cannot open file '" << fileName - << "' for output.\n" << logofs_flush; - #endif - - goto SplitStoreSaveError; - } - - fileHeader = new unsigned char[SPLIT_HEADER_SIZE]; - - if (fileHeader == NULL) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Cannot allocate space for " - << "NX image header.\n" << logofs_flush; - #endif - - goto SplitStoreSaveError; - } - - // - // Leave 3 bytes for future use. Please note - // that, on some CPUs, we can't use PutULONG() - // to write integers that are not aligned to - // the word boundary. - // - - *fileHeader = opcode; - - *(fileHeader + 1) = 0; - *(fileHeader + 2) = 0; - *(fileHeader + 3) = 0; - - PutULONG(dataSize, fileHeader + 4, false); - PutULONG(compressedSize, fileHeader + 8, false); - - splitSize = (compressedSize > 0 ? compressedSize : dataSize); - - if (PutData(fileStream, fileHeader, SPLIT_HEADER_SIZE) < 0 || - PutData(fileStream, data, splitSize) < 0) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Cannot write to NX " - << "image file '" << fileName << "'.\n" - << logofs_flush; - #endif - - goto SplitStoreSaveError; - } - - // - // Check if all the data was written on the - // disk and, if not, remove the faulty copy. - // - - FlushData(fileStream); - - if (CheckData(fileStream) < 0) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Failed to write NX " - << "image file '" << fileName << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Failed to write NX " - << "image file '" << fileName << "'.\n"; - - goto SplitStoreSaveError; - } - - #ifdef TEST - *logofs << "SplitStore: Saved split to file '" << fileName - << "' with data size " << dataSize << " and " - << "compressed data size " << compressedSize - << ".\n" << logofs_flush; - #endif - - delete fileStream; - - delete [] fileName; - delete [] fileHeader; - - EnableSignals(); - - // - // Update the timestamp as the operation - // may have taken some time. - // - - getNewTimestamp(); - - return 1; - -SplitStoreSaveError: - - delete fileStream; - - if (fileName != NULL) - { - unlink(fileName); - } - - delete [] fileName; - delete [] fileHeader; - - EnableSignals(); - - return -1; -} - -int SplitStore::find(Split *split) -{ - const char *fileName = name(split -> checksum_); - - if (fileName == NULL) - { - return 0; - } - - #ifdef DEBUG - *logofs << "SplitStore: Going to find split OPCODE#" - << (unsigned) split -> store_ -> opcode() - << " in file '" << fileName << "'.\n" - << logofs_flush; - #endif - - // - // Check if the file exists and, at the - // same time, update the modification - // time to prevent its deletion. - // - - if (utime(fileName, NULL) == 0) - { - #ifdef TEST - *logofs << "SplitStore: Found split OPCODE#" - << (unsigned) split -> store_ -> opcode() - << " in file '" << fileName << "'.\n" - << logofs_flush; - #endif - - delete [] fileName; - - return 1; - } - - #ifdef TEST - *logofs << "SplitStore: WARNING! Can't find split " - << "OPCODE#" << (unsigned) split -> store_ -> - opcode() << " in file '" << fileName - << "'.\n" << logofs_flush; - #endif - - delete [] fileName; - - return 0; -} - -int SplitStore::load(Split *split) -{ - // - // Check if loading the image is enabled. - // - - if (split -> load_ == 0) - { - return 0; - } - - const char *fileName = name(split -> checksum_); - - if (fileName == NULL) - { - return 0; - } - - unsigned char fileOpcode; - - int fileSize; - int fileCSize; - - istream *fileStream = NULL; - - unsigned char *fileHeader = NULL; - - DisableSignals(); - - #ifdef DEBUG - *logofs << "SplitStore: Going to load split OPCODE#" - << (unsigned int) split -> store_ -> opcode() - << " from file '" << fileName << "'.\n" - << logofs_flush; - #endif - - fileStream = new ifstream(fileName, ios::in | ios::binary); - - if (CheckData(fileStream) < 0) - { - #ifdef TEST - *logofs << "SplitStore: WARNING! Can't open image file '" - << fileName << "' on disk.\n" << logofs_flush; - #endif - - goto SplitStoreLoadError; - } - - fileHeader = new unsigned char[SPLIT_HEADER_SIZE]; - - if (fileHeader == NULL) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Cannot allocate space for " - << "NX image header.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot allocate space for " - << "NX image header.\n"; - - goto SplitStoreLoadError; - } - - if (GetData(fileStream, fileHeader, SPLIT_HEADER_SIZE) < 0) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Cannot read header from " - << "NX image file '" << fileName << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Cannot read header from " - << "NX image file '" << fileName << "'.\n"; - - goto SplitStoreLoadError; - } - - fileOpcode = *fileHeader; - - fileSize = GetULONG(fileHeader + 4, false); - fileCSize = GetULONG(fileHeader + 8, false); - - // - // Don't complain if we find that data was saved - // in compressed form even if we were not aware - // of the compressed data size. The remote side - // compresses the data only at the time it starts - // the transferral of the split. We replace our - // copy of the data with whatever we find on the - // disk. - // - - if (fileOpcode != split -> store_ -> opcode() || - fileSize != split -> d_size_ || - fileSize > control -> MaximumRequestSize || - fileCSize > control -> MaximumRequestSize) - - { - #ifdef TEST - *logofs << "SplitStore: PANIC! Corrupted image file '" << fileName - << "'. Expected " << (unsigned int) split -> store_ -> opcode() - << "/" << split -> d_size_ << "/" << split -> c_size_ << " found " - << (unsigned int) fileOpcode << "/" << fileSize << "/" - << fileCSize << ".\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Corrupted image file '" << fileName - << "'. Expected " << (unsigned int) split -> store_ -> opcode() - << "/" << split -> d_size_ << "/" << split -> c_size_ << " found " - << (unsigned int) fileOpcode << "/" << fileSize << "/" - << fileCSize << ".\n"; - - goto SplitStoreLoadError; - } - - // - // Update the data size with the size - // we got from the disk record. - // - - split -> d_size_ = fileSize; - split -> c_size_ = fileCSize; - - unsigned int splitSize; - - if (fileCSize > 0) - { - splitSize = fileCSize; - } - else - { - splitSize = fileSize; - } - - // - // Allocate a new buffer if we didn't - // do that already or if the size is - // different. - // - - if (split -> data_.size() != splitSize) - { - split -> data_.clear(); - - split -> data_.resize(splitSize); - } - - if (GetData(fileStream, split -> data_.begin(), splitSize) < 0) - { - #ifdef PANIC - *logofs << "SplitStore: PANIC! Cannot read data from " - << "NX image file '" << fileName << "'.\n" - << logofs_flush; - #endif - - cerr << "Warning" << ": Cannot read data from " - << "NX image file '" << fileName << "'.\n"; - - goto SplitStoreLoadError; - } - - delete fileStream; - - delete [] fileHeader; - delete [] fileName; - - EnableSignals(); - - // - // Update the timestamp as the operation - // may have taken some time. - // - - getNewTimestamp(); - - return 1; - -SplitStoreLoadError: - - delete fileStream; - - unlink(fileName); - - delete [] fileName; - delete [] fileHeader; - - EnableSignals(); - - return -1; -} - -Split *CommitStore::pop() -{ - if (splits_ -> size() == 0) - { - #ifdef TEST - *logofs << "CommitStore: The commit store is empty.\n" - << logofs_flush; - #endif - - return NULL; - } - - Split *split = *(splits_ -> begin()); - - splits_ -> pop_front(); - - #ifdef TEST - *logofs << "CommitStore: Removed commit split at the head " - << "of the list with resource " << split -> resource_ - << " request " << (unsigned) split -> store_ -> - opcode() << " position " << split -> position_ - << ".\n" << logofs_flush; - #endif - - return split; -} - -int CommitStore::expand(Split *split, unsigned char *buffer, const int size) -{ - #ifdef TEST - *logofs << "CommitStore: Expanding split data with " - << size << " bytes to write.\n" - << logofs_flush; - #endif - - #ifdef TEST - - if (size < split -> i_size_ + split -> d_size_) - { - #ifdef PANIC - *logofs << "CommitStore: PANIC! Wrong size of the provided " - << "buffer. It should be " << split -> i_size_ + - split -> d_size_ << " instead of " << size - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Wrong size of the provided " - << "buffer. It should be " << split -> i_size_ + - split -> d_size_ << " instead of " << size - << ".\n"; - - HandleAbort(); - } - - #endif - - #ifdef DEBUG - *logofs << "CommitStore: Copying " << split -> i_size_ - << " bytes of identity.\n" << logofs_flush; - #endif - - memcpy(buffer, split -> identity_.begin(), split -> i_size_); - - // - // Copy data, if any, to the buffer. - // - - if (size > split -> i_size_) - { - // - // Check if message has been stored - // in compressed format. - // - - if (split -> c_size_ == 0) - { - #ifdef DEBUG - *logofs << "CommitStore: Copying " << split -> d_size_ - << " bytes of plain data.\n" << logofs_flush; - #endif - - memcpy(buffer + split -> i_size_, split -> data_.begin(), split -> d_size_); - } - else - { - #ifdef DEBUG - *logofs << "CommitStore: Decompressing " << split -> c_size_ - << " bytes and copying " << split -> d_size_ - << " bytes of data.\n" << logofs_flush; - #endif - - if (compressor_ -> - decompressBuffer(buffer + split -> i_size_, - split -> d_size_, split -> data_.begin(), - split -> c_size_) < 0) - { - #ifdef PANIC - *logofs << "CommitStore: PANIC! Split data decompression failed.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Split data decompression failed.\n"; - - return -1; - } - } - } - - return 1; -} - -int CommitStore::update(Split *split) -{ - if (split -> action_ != IS_ADDED) - { - return 0; - } - - // - // We don't need the identity data at - // the encoding side. - // - - if (split -> identity_.size() == 0) - { - #ifdef TEST - *logofs << "SplitStore: Going to update the size " - << "for object at position " << split -> position_ - << " with data size " << split -> d_size_ - << " and compressed data size " << split -> - c_size_ << ".\n" << logofs_flush; - #endif - - split -> store_ -> updateData(split -> position_, split -> d_size_, - split -> c_size_); - } - else - { - #ifdef TEST - *logofs << "SplitStore: Going to update data and size " - << "for object at position " << split -> position_ - << " with data size " << split -> d_size_ - << " and compressed data size " << split -> - c_size_ << ".\n" << logofs_flush; - #endif - - split -> store_ -> updateData(split -> position_, split -> data_.begin(), - split -> d_size_, split -> c_size_); - } - - // - // Unlock message so that we can remove - // or save it on disk at shutdown. - // - - if (split -> action_ == IS_ADDED) - { - split -> store_ -> unlock(split -> position_); - - #ifdef TEST - - validate(split); - - #endif - } - - return 1; -} - -int CommitStore::validate(Split *split) -{ - MessageStore *store = split -> store_; - - int p, n, s; - - s = store -> cacheSlots; - - for (p = 0, n = 0; p < s; p++) - { - if (store -> getLocks(p) == 1) - { - n++; - } - else if (store -> getLocks(p) != 0) - { - #ifdef PANIC - *logofs << "CommitStore: PANIC! Repository for OPCODE#" - << (unsigned int) store -> opcode() << " has " - << store -> getLocks(p) << " locks for message " - << "at position " << p << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Repository for OPCODE#" - << (unsigned int) store -> opcode() << " has " - << store -> getLocks(p) << " locks for message " - << "at position " << p << ".\n"; - - HandleAbort(); - } - } - - #ifdef TEST - *logofs << "CommitStore: Repository for OPCODE#" - << (unsigned int) store -> opcode() - << " has " << n << " locked messages.\n" - << logofs_flush; - #endif - - return 1; -} diff --git a/nxcomp/Split.h b/nxcomp/Split.h deleted file mode 100644 index ee5eae7fe..000000000 --- a/nxcomp/Split.h +++ /dev/null @@ -1,543 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Split_H -#define Split_H - -#include "Types.h" -#include "Timestamp.h" -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Define this to know how many splits -// are allocated and deallocated. -// - -#undef REFERENCES - -// -// Size of header of messages saved on -// disk. -// - -#define SPLIT_HEADER_SIZE 12 - -// -// This class is used to divide big messages -// in smaller chunks and send them at idle -// time. -// - -class EncodeBuffer; -class DecodeBuffer; - -class SplitStore; -class CommitStore; - -// -// Preferred message streaming policy. -// - -typedef enum -{ - split_none = -1, - split_async = 1, - split_sync - -} T_split_mode; - -// -// Current state of the split. Used to -// implement the state machine. -// - -typedef enum -{ - split_undefined = -1, - split_added, - split_missed, - split_loaded, - split_aborted, - split_notified - -} T_split_state; - -class Split -{ - friend class SplitStore; - friend class CommitStore; - - public: - - Split(); - - ~Split(); - - // - // Note that, differently from the message - // store, the split store doesn't account - // for the data offset when dealing with - // the data. This means that both the size_ - // and c_size members represent the actual - // size of the data part. - // - - void compressedSize(int size) - { - c_size_ = size; - - store_ -> validateSize(d_size_, c_size_); - } - - int compressedSize() - { - return c_size_; - } - - int plainSize() - { - return i_size_ + d_size_; - } - - T_checksum getChecksum() - { - return checksum_; - } - - MessageStore *getStore() - { - return store_; - } - - T_split_state getState() - { - return state_; - } - - T_store_action getAction() - { - return action_; - } - - // - // We may need to find the resource - // associated to the split message - // because old protocol version use - // a single store for all splits. - // - - int getResource() - { - return resource_; - } - - int getRequest() - { - return store_ -> opcode(); - } - - int getPosition() - { - return position_; - } - - T_split_mode getMode() - { - return mode_; - } - - void setPolicy(int load, int save) - { - load_ = load; - save_ = save; - } - - void setState(T_split_state state) - { - state_ = state; - } - - private: - - // - // The agent's resource which is splitting - // the message. - // - - int resource_; - - // - // Where to find the message in the message - // store or the X sequence number of the - // original request, in recent versions. - // - - int position_; - - // - // Which store is involved. - // - - MessageStore *store_; - - // - // Identity size of the message. - // - - int i_size_; - - // - // This is the uncompressed data size of the - // original message. - // - - int d_size_; - - // - // This is the size of the compressed data, - // if the data is stored in this form. - // - - int c_size_; - - // - // Size of the data buffer, as known by the - // encoding side. This field is only used at - // the decoding side. The remote size can be - // different from the actual data size, if - // the encoding side did not confirm that it - // received the abort split event. - // - - int r_size_; - - // - // Position in the data buffer that will be - // the target of the next send or receive - // operation while streaming the message. - // - - int next_; - - // - // Load or save the split to disk. - // - - int load_; - int save_; - - // - // Checksum of the original message. - // - - T_checksum checksum_; - - // - // Was this split confirmed or aborted? - // - - T_split_state state_; - - // - // What's the policy for sending this split? - // - - T_split_mode mode_; - - // - // Operation that had been performed on the - // store at the time the split was added. - // - - T_store_action action_; - - // - // Container for the identity and data part - // of the X message. - // - - T_data identity_; - T_data data_; - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -class SplitStore -{ - public: - - SplitStore(StaticCompressor *compressor, CommitStore *commits, int resource); - - ~SplitStore(); - - Split *getFirstSplit() const - { - if (splits_ -> size() > 0) - { - return (*(splits_ -> begin())); - } - - return NULL; - } - - Split *getLastSplit() const - { - if (splits_ -> size() > 0) - { - return (*(--(splits_ -> end()))); - } - - return NULL; - } - - int getNodeSize(const Split *split) const - { - // - // Take in account 64 bytes of overhead - // for each node. - // - - return (sizeof(class Split) + 64 + - split -> i_size_ + split -> d_size_); - } - - int getStorageSize() - { - return splitStorageSize_; - } - - static int getTotalSize() - { - return totalSplitSize_; - } - - static int getTotalStorageSize() - { - return totalSplitStorageSize_; - } - - int getResource() - { - return resource_; - } - - int getSize() - { - return splits_ -> size(); - } - - T_splits *getSplits() - { - return splits_; - } - - // - // Used, respectively, at the encoding - // and decoding side. - // - - Split *add(MessageStore *store, int resource, T_split_mode mode, - int position, T_store_action action, T_checksum checksum, - const unsigned char *buffer, const int size); - - Split *add(MessageStore *store, int resource, int position, - T_store_action action, T_checksum checksum, - unsigned char *buffer, const int size); - - // - // Handle the streaming of the message data. - // - - int send(EncodeBuffer &encodeBuffer, int packetSize); - - int receive(DecodeBuffer &decodeBuffer); - - // - // Remove the top element of the split store - // and update the storage size. - // - - void remove(Split *split); - - // - // Load the message from disk and replace the - // message in the store with the new copy. - // - - int load(Split *split); - - // - // Save the data to disk after the message has - // been recomposed at the local side. - // - - int save(Split *split); - - // - // Find the message on disk and update the last - // modification time. This is currently unused. - // - - int find(Split *split); - - // - // Remove the element on top of the queue and - // discard any split data that still needs to - // be transferred. - // - - Split *pop(); - - // - // Dump the content of the store. - // - - void dump(); - - protected: - - // - // Repository where to add the splits. - // - - T_splits *splits_; - - // - // Compress and decompress the data payload. - // - - StaticCompressor *compressor_; - - private: - - int start(EncodeBuffer &encodeBuffer); - - int start(DecodeBuffer &decodeBuffer); - - void push(Split *split); - - // - // Determine the name of the file object based - // on the checksum. - // - - const char *name(const T_checksum checksum); - - // - // The number of elements and data bytes - // in the repository. - // - - int splitStorageSize_; - - static int totalSplitSize_; - static int totalSplitStorageSize_; - - // - // Current element being transferred. - // - - T_splits::iterator current_; - - // - // Repository where to move the splits - // after they are completely recomposed. - // - - CommitStore *commits_; - - // - // Index in the client store or none, - // if this is a commit store. - // - - int resource_; - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -class CommitStore : public SplitStore -{ - // - // This is just a split store. - // - - public: - - CommitStore(StaticCompressor *compressor) - - : SplitStore(compressor, NULL, nothing) - { - } - - // - // Move identity and data of the split to the - // provided buffer, uncompressing the message, - // if needed. - // - - int expand(Split *split, unsigned char *buffer, const int size); - - // - // We recomposed the data part. If the message - // was originally added to the message store, - // replace the data and/or update the size. - // - - int update(Split *split); - - // - // Remove the split from the commit queue. - // - - Split *pop(); - - // - // This is just used for debug. It checks - // if any message in the message store has - // an invalid number of locks. - // - - int validate(Split *split); -}; - -#endif /* Split_H */ diff --git a/nxcomp/StaticCompressor.cpp b/nxcomp/StaticCompressor.cpp deleted file mode 100644 index 93103af41..000000000 --- a/nxcomp/StaticCompressor.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Z.h" -#include "Misc.h" -#include "Control.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -#include "StaticCompressor.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -StaticCompressor::StaticCompressor(int compressionLevel, - int compressionThreshold) -{ - buffer_ = NULL; - bufferSize_ = 0; - - compressionStream_.zalloc = (alloc_func) 0; - compressionStream_.zfree = (free_func) 0; - compressionStream_.opaque = (voidpf) 0; - - decompressionStream_.zalloc = (alloc_func) 0; - decompressionStream_.zfree = (free_func) 0; - decompressionStream_.opaque = (void *) 0; - - decompressionStream_.next_in = (Bytef *) 0; - decompressionStream_.avail_in = 0; - - #ifdef TEST - *logofs << "StaticCompressor: Compression level is " - << compressionLevel << ".\n" << logofs_flush; - #endif - - int result = deflateInit2(&compressionStream_, compressionLevel, Z_DEFLATED, - 15, 9, Z_DEFAULT_STRATEGY); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Cannot initialize the " - << "compression stream. Error is '" << zError(result) - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot initialize the compression " - << "stream. Error is '" << zError(result) << "'.\n"; - - HandleAbort(); - } - - result = inflateInit2(&decompressionStream_, 15); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Cannot initialize the " - << "decompression stream. Error is '" << zError(result) - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot initialize the decompression " - << "stream. Error is '" << zError(result) << "'.\n"; - - HandleAbort(); - } - - #ifdef TEST - *logofs << "StaticCompressor: Compression threshold is " - << compressionThreshold << ".\n" << logofs_flush; - #endif - - threshold_ = compressionThreshold; -} - -StaticCompressor::~StaticCompressor() -{ - int result = deflateEnd(&compressionStream_); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Cannot deinitialize the " - << "compression stream. Error is '" << zError(result) - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot deinitialize the compression " - << "stream. Error is '" << zError(result) << "'.\n"; - } - - result = inflateEnd(&decompressionStream_); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Cannot deinitialize the " - << "decompression stream. Error is '" << zError(result) - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot deinitialize the decompression " - << "stream. Error is '" << zError(result) << "'.\n"; - } - - delete [] buffer_; -} - -// -// This function compresses and encodes the compressed -// buffer. It returns a pointer to the internal buffer -// where data was compressed. -// - -int StaticCompressor::compressBuffer(const unsigned char *plainBuffer, - const unsigned int plainSize, - unsigned char *&compressedBuffer, - unsigned int &compressedSize, - EncodeBuffer &encodeBuffer) -{ - if (control -> LocalDataCompression == 0 || - compressBuffer(plainBuffer, plainSize, - compressedBuffer, compressedSize) <= 0) - { - encodeBuffer.encodeBoolValue(0); - - encodeBuffer.encodeMemory(plainBuffer, plainSize); - - return 0; - } - else - { - encodeBuffer.encodeBoolValue(1); - - encodeBuffer.encodeValue(compressedSize, 32, 14); - encodeBuffer.encodeValue(plainSize, 32, 14); - - encodeBuffer.encodeMemory(compressedBuffer, compressedSize); - - return 1; - } -} - -// -// This function compresses data into a dynamically -// allocated buffer and returns a pointer to it, so -// application must copy data before the next call. -// - -int StaticCompressor::compressBuffer(const unsigned char *plainBuffer, - const unsigned int plainSize, - unsigned char *&compressedBuffer, - unsigned int &compressedSize) -{ - #ifdef DEBUG - *logofs << "StaticCompressor: Called for buffer at " - << (void *) plainBuffer << ".\n" - << logofs_flush; - #endif - - compressedSize = plainSize; - - if (plainSize < (unsigned int) threshold_) - { - #ifdef TEST - *logofs << "StaticCompressor: Leaving buffer unchanged. " - << "Plain size is " << plainSize << " with threshold " - << (unsigned int) threshold_ << ".\n" << logofs_flush; - #endif - - return 0; - } - - // - // Determine the size of the temporary - // buffer. - // - - unsigned int newSize = plainSize + (plainSize / 1000) + 12; - - // - // Allocate a new buffer if it grows - // beyond 64K. - // - - if (buffer_ == NULL || (bufferSize_ > 65536 && - newSize < bufferSize_ / 2) || newSize > bufferSize_) - { - delete [] buffer_; - - buffer_ = new unsigned char[newSize]; - - if (buffer_ == NULL) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Can't allocate compression " - << "buffer of " << newSize << " bytes. Error is " << EGET() - << " ' " << ESTR() << "'.\n" << logofs_flush; - #endif - - cerr << "Warning" << ": Can't allocate compression buffer of " - << newSize << " bytes. Error is " << EGET() - << " '" << ESTR() << "'.\n"; - - bufferSize_ = 0; - - return 0; - } - - bufferSize_ = newSize; - } - - unsigned int resultingSize = newSize; - - int result = ZCompress(&compressionStream_, buffer_, &resultingSize, - plainBuffer, plainSize); - - if (result == Z_OK) - { - if (resultingSize > newSize) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Overflow in compression " - << "buffer size. " << "Expected size was " << newSize - << " while it is " << resultingSize << ".\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Overflow in compress buffer size. " - << "Expected size was " << newSize << " while it is " - << resultingSize << ".\n"; - - return -1; - } - else if (resultingSize >= plainSize) - { - #ifdef TEST - *logofs << "StaticCompressor: Leaving buffer unchanged. " - << "Plain size is " << plainSize << " compressed " - << "size is " << resultingSize << ".\n" - << logofs_flush; - #endif - - return 0; - } - - compressedBuffer = buffer_; - compressedSize = resultingSize; - - #ifdef TEST - *logofs << "StaticCompressor: Compressed buffer from " - << plainSize << " to " << resultingSize - << " bytes.\n" << logofs_flush; - #endif - - return 1; - } - - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Failed compression of buffer. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failed compression of buffer. " - << "Error is '" << zError(result) << "'.\n"; - - return -1; -} - -int StaticCompressor::decompressBuffer(unsigned char *plainBuffer, - unsigned int plainSize, - const unsigned char *&compressedBuffer, - unsigned int &compressedSize, - DecodeBuffer &decodeBuffer) -{ - #ifdef DEBUG - *logofs << "StaticCompressor: Called for buffer at " - << (void *) plainBuffer << ".\n" - << logofs_flush; - #endif - - unsigned int value; - - decodeBuffer.decodeBoolValue(value); - - if (value == 0) - { - memcpy(plainBuffer, - decodeBuffer.decodeMemory(plainSize), - plainSize); - - return 0; - } - - unsigned int checkSize = plainSize; - - decodeBuffer.decodeValue(value, 32, 14); - compressedSize = value; - - decodeBuffer.decodeValue(value, 32, 14); - checkSize = value; - - // - // If caller needs the original compressed - // data it must copy this to its own buffer - // before using any further decode function. - // - - compressedBuffer = decodeBuffer.decodeMemory(compressedSize); - - int result = ZDecompress(&decompressionStream_, plainBuffer, &checkSize, - compressedBuffer, compressedSize); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Failure decompressing buffer. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Failure decompressing buffer. " - << "Error is '" << zError(result) << "'.\n"; - - return -1; - } - else if (plainSize != checkSize) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Expected decompressed size was " - << plainSize << " while it is " << checkSize - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Expected decompressed size was " - << plainSize << " while it is " << checkSize - << ".\n"; - - return -1; - } - - return 1; -} - -// -// This is used to uncompress on-the-fly -// messages whose data has been stored -// in compressed format. -// - -int StaticCompressor::decompressBuffer(unsigned char *plainBuffer, - const unsigned int plainSize, - const unsigned char *compressedBuffer, - const unsigned int compressedSize) -{ - #ifdef TEST - *logofs << "StaticCompressor: Called for buffer at " - << (void *) plainBuffer << ".\n" - << logofs_flush; - #endif - - unsigned int checkSize = plainSize; - - int result = ZDecompress(&decompressionStream_, plainBuffer, &checkSize, - compressedBuffer, compressedSize); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Failure decompressing buffer. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - return -1; - } - - if (plainSize != checkSize) - { - #ifdef PANIC - *logofs << "StaticCompressor: PANIC! Expected decompressed size was " - << plainSize << " while it is " << checkSize - << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Expected decompressed size was " - << plainSize << " while it is " << checkSize - << ".\n"; - - return -1; - } - - #ifdef TEST - *logofs << "StaticCompressor: Decompressed buffer from " - << compressedSize << " to " << plainSize - << " bytes.\n" << logofs_flush; - #endif - - return 1; -} diff --git a/nxcomp/StaticCompressor.h b/nxcomp/StaticCompressor.h deleted file mode 100644 index e0b81a527..000000000 --- a/nxcomp/StaticCompressor.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef StaticCompressor_H -#define StaticCompressor_H - -#include "Z.h" - -class EncodeBuffer; -class DecodeBuffer; - -class StaticCompressor -{ - public: - - StaticCompressor(int compressionLevel, int compressionThreshold); - - ~StaticCompressor(); - - int compressBuffer(const unsigned char *plainBuffer, const unsigned int plainSize, - unsigned char *&compressedBuffer, unsigned int &compressedSize, - EncodeBuffer &encodeBuffer); - - int compressBuffer(const unsigned char *plainBuffer, const unsigned int plainSize, - unsigned char *&compressedBuffer, unsigned int &compressedSize); - - int decompressBuffer(unsigned char *plainBuffer, unsigned int plainSize, - const unsigned char *&compressedBuffer, unsigned int &compressedSize, - DecodeBuffer &decodeBuffer); - - int decompressBuffer(unsigned char *plainBuffer, const unsigned int plainSize, - const unsigned char *compressedBuffer, const unsigned compressedSize); - - static int isCompressionLevel(int compressionLevel) - { - return (compressionLevel == Z_DEFAULT_COMPRESSION || - (compressionLevel >= Z_NO_COMPRESSION && - compressionLevel <= Z_BEST_COMPRESSION)); - } - - int fullReset() - { - return (deflateReset(&compressionStream_) == Z_OK && - inflateReset(&decompressionStream_) == Z_OK); - } - - private: - - z_stream compressionStream_; - z_stream decompressionStream_; - - unsigned char *buffer_; - unsigned int bufferSize_; - - int threshold_; -}; - -#endif diff --git a/nxcomp/Statistics.cpp b/nxcomp/Statistics.cpp deleted file mode 100644 index baad7ef60..000000000 --- a/nxcomp/Statistics.cpp +++ /dev/null @@ -1,2003 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include - -#include "Statistics.h" - -#include "Control.h" - -#include "Proxy.h" - -#include "ClientStore.h" -#include "ServerStore.h" - -// -// Length of temporary buffer -// used to format output. -// - -#define FORMAT_LENGTH 1024 - -// -// Log level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Note that when presenting statistics we invert the -// correct semantics of X client and server entities. -// This is questionable, but matches the user's pers- -// pective of running remote X applications on its -// local client. -// - -Statistics::Statistics(Proxy *proxy) : proxy_(proxy) -{ - transportPartial_.idleTime_ = 0; - transportPartial_.readTime_ = 0; - transportPartial_.writeTime_ = 0; - transportPartial_.proxyBytesIn_ = 0; - transportPartial_.proxyBytesOut_ = 0; - transportPartial_.proxyFramesIn_ = 0; - transportPartial_.proxyFramesOut_ = 0; - transportPartial_.proxyWritesOut_ = 0; - transportPartial_.compressedBytesIn_ = 0; - transportPartial_.compressedBytesOut_ = 0; - transportPartial_.decompressedBytesIn_ = 0; - transportPartial_.decompressedBytesOut_ = 0; - transportPartial_.framingBitsOut_ = 0; - - transportTotal_.idleTime_ = 0; - transportTotal_.readTime_ = 0; - transportTotal_.writeTime_ = 0; - transportTotal_.proxyBytesIn_ = 0; - transportTotal_.proxyBytesOut_ = 0; - transportTotal_.proxyFramesIn_ = 0; - transportTotal_.proxyFramesOut_ = 0; - transportTotal_.proxyWritesOut_ = 0; - transportTotal_.compressedBytesIn_ = 0; - transportTotal_.compressedBytesOut_ = 0; - transportTotal_.decompressedBytesIn_ = 0; - transportTotal_.decompressedBytesOut_ = 0; - transportTotal_.framingBitsOut_ = 0; - - for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) - { - protocolPartial_.requestCached_[i] = 0; - protocolPartial_.requestReplied_[i] = 0; - protocolPartial_.requestCount_[i] = 0; - protocolPartial_.requestBitsIn_[i] = 0; - protocolPartial_.requestBitsOut_[i] = 0; - - protocolPartial_.renderRequestCached_[i] = 0; - protocolPartial_.renderRequestCount_[i] = 0; - protocolPartial_.renderRequestBitsIn_[i] = 0; - protocolPartial_.renderRequestBitsOut_[i] = 0; - - protocolPartial_.replyCached_[i] = 0; - protocolPartial_.replyCount_[i] = 0; - protocolPartial_.replyBitsIn_[i] = 0; - protocolPartial_.replyBitsOut_[i] = 0; - - protocolPartial_.eventCached_[i] = 0; - protocolPartial_.eventCount_[i] = 0; - protocolPartial_.eventBitsIn_[i] = 0; - protocolPartial_.eventBitsOut_[i] = 0; - - protocolTotal_.requestCached_[i] = 0; - protocolTotal_.requestReplied_[i] = 0; - protocolTotal_.requestCount_[i] = 0; - protocolTotal_.requestBitsIn_[i] = 0; - protocolTotal_.requestBitsOut_[i] = 0; - - protocolTotal_.renderRequestCached_[i] = 0; - protocolTotal_.renderRequestCount_[i] = 0; - protocolTotal_.renderRequestBitsIn_[i] = 0; - protocolTotal_.renderRequestBitsOut_[i] = 0; - - protocolTotal_.replyCached_[i] = 0; - protocolTotal_.replyCount_[i] = 0; - protocolTotal_.replyBitsIn_[i] = 0; - protocolTotal_.replyBitsOut_[i] = 0; - - protocolTotal_.eventCached_[i] = 0; - protocolTotal_.eventCount_[i] = 0; - protocolTotal_.eventBitsIn_[i] = 0; - protocolTotal_.eventBitsOut_[i] = 0; - } - - protocolPartial_.cupsCount_ = 0; - protocolPartial_.cupsBitsIn_ = 0; - protocolPartial_.cupsBitsOut_ = 0; - - protocolPartial_.smbCount_ = 0; - protocolPartial_.smbBitsIn_ = 0; - protocolPartial_.smbBitsOut_ = 0; - - protocolPartial_.mediaCount_ = 0; - protocolPartial_.mediaBitsIn_ = 0; - protocolPartial_.mediaBitsOut_ = 0; - - protocolPartial_.httpCount_ = 0; - protocolPartial_.httpBitsIn_ = 0; - protocolPartial_.httpBitsOut_ = 0; - - protocolPartial_.fontCount_ = 0; - protocolPartial_.fontBitsIn_ = 0; - protocolPartial_.fontBitsOut_ = 0; - - protocolPartial_.slaveCount_ = 0; - protocolPartial_.slaveBitsIn_ = 0; - protocolPartial_.slaveBitsOut_ = 0; - - protocolTotal_.cupsCount_ = 0; - protocolTotal_.cupsBitsIn_ = 0; - protocolTotal_.cupsBitsOut_ = 0; - - protocolTotal_.smbCount_ = 0; - protocolTotal_.smbBitsIn_ = 0; - protocolTotal_.smbBitsOut_ = 0; - - protocolTotal_.mediaCount_ = 0; - protocolTotal_.mediaBitsIn_ = 0; - protocolTotal_.mediaBitsOut_ = 0; - - protocolTotal_.httpCount_ = 0; - protocolTotal_.httpBitsIn_ = 0; - protocolTotal_.httpBitsOut_ = 0; - - protocolTotal_.fontCount_ = 0; - protocolTotal_.fontBitsIn_ = 0; - protocolTotal_.fontBitsOut_ = 0; - - protocolTotal_.slaveCount_ = 0; - protocolTotal_.slaveBitsIn_ = 0; - protocolTotal_.slaveBitsOut_ = 0; - - packedPartial_.packedBytesIn_ = 0; - packedPartial_.packedBytesOut_ = 0; - - packedTotal_.packedBytesIn_ = 0; - packedTotal_.packedBytesOut_ = 0; - - splitPartial_.splitCount_ = 0; - splitPartial_.splitAborted_ = 0; - splitPartial_.splitAbortedBytesOut_ = 0; - - splitTotal_.splitCount_ = 0; - splitTotal_.splitAborted_ = 0; - splitTotal_.splitAbortedBytesOut_ = 0; - - overallPartial_.overallBytesIn_ = 0; - overallPartial_.overallBytesOut_ = 0; - - overallTotal_.overallBytesIn_ = 0; - overallTotal_.overallBytesOut_ = 0; - - proxyData_.protocolCount_ = 0; - proxyData_.controlCount_ = 0; - proxyData_.splitCount_ = 0; - proxyData_.dataCount_ = 0; - - proxyData_.streamRatio_ = 1; - - startShortFrameTs_ = getTimestamp(); - startLongFrameTs_ = getTimestamp(); - startFrameTs_ = getTimestamp(); - - bytesInShortFrame_ = 0; - bytesInLongFrame_ = 0; - - bitrateInShortFrame_ = 0; - bitrateInLongFrame_ = 0; - - topBitrate_ = 0; - - congestionInFrame_ = 0; -} - -Statistics::~Statistics() -{ -} - -int Statistics::resetPartialStats() -{ - transportPartial_.idleTime_ = 0; - transportPartial_.readTime_ = 0; - transportPartial_.writeTime_ = 0; - transportPartial_.proxyBytesIn_ = 0; - transportPartial_.proxyBytesOut_ = 0; - transportPartial_.proxyFramesIn_ = 0; - transportPartial_.proxyFramesOut_ = 0; - transportPartial_.proxyWritesOut_ = 0; - transportPartial_.compressedBytesIn_ = 0; - transportPartial_.compressedBytesOut_ = 0; - transportPartial_.decompressedBytesIn_ = 0; - transportPartial_.decompressedBytesOut_ = 0; - transportPartial_.framingBitsOut_ = 0; - - for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) - { - protocolPartial_.requestCached_[i] = 0; - protocolPartial_.requestReplied_[i] = 0; - protocolPartial_.requestCount_[i] = 0; - protocolPartial_.requestBitsIn_[i] = 0; - protocolPartial_.requestBitsOut_[i] = 0; - - protocolPartial_.renderRequestCached_[i] = 0; - protocolPartial_.renderRequestCount_[i] = 0; - protocolPartial_.renderRequestBitsIn_[i] = 0; - protocolPartial_.renderRequestBitsOut_[i] = 0; - - protocolPartial_.replyCached_[i] = 0; - protocolPartial_.replyCount_[i] = 0; - protocolPartial_.replyBitsIn_[i] = 0; - protocolPartial_.replyBitsOut_[i] = 0; - - protocolPartial_.eventCached_[i] = 0; - protocolPartial_.eventCount_[i] = 0; - protocolPartial_.eventBitsIn_[i] = 0; - protocolPartial_.eventBitsOut_[i] = 0; - } - - protocolPartial_.cupsCount_ = 0; - protocolPartial_.cupsBitsIn_ = 0; - protocolPartial_.cupsBitsOut_ = 0; - - protocolPartial_.smbCount_ = 0; - protocolPartial_.smbBitsIn_ = 0; - protocolPartial_.smbBitsOut_ = 0; - - protocolPartial_.mediaCount_ = 0; - protocolPartial_.mediaBitsIn_ = 0; - protocolPartial_.mediaBitsOut_ = 0; - - protocolPartial_.httpCount_ = 0; - protocolPartial_.httpBitsIn_ = 0; - protocolPartial_.httpBitsOut_ = 0; - - protocolPartial_.fontCount_ = 0; - protocolPartial_.fontBitsIn_ = 0; - protocolPartial_.fontBitsOut_ = 0; - - protocolPartial_.slaveCount_ = 0; - protocolPartial_.slaveBitsIn_ = 0; - protocolPartial_.slaveBitsOut_ = 0; - - packedPartial_.packedBytesIn_ = 0; - packedPartial_.packedBytesOut_ = 0; - - splitPartial_.splitCount_ = 0; - splitPartial_.splitAborted_ = 0; - splitPartial_.splitAbortedBytesOut_ = 0; - - overallPartial_.overallBytesIn_ = 0; - overallPartial_.overallBytesOut_ = 0; - - return 1; -} - -void Statistics::addCompressedBytes(unsigned int bytesIn, unsigned int bytesOut) -{ - transportPartial_.compressedBytesIn_ += bytesIn; - transportTotal_.compressedBytesIn_ += bytesIn; - - transportPartial_.compressedBytesOut_ += bytesOut; - transportTotal_.compressedBytesOut_ += bytesOut; - - double ratio = bytesIn / bytesOut; - - if (ratio < 1) - { - ratio = 1; - } - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! Old ratio was " - << proxyData_.streamRatio_ << " current is " - << (double) ratio << " new ratio is " << (double) - ((proxyData_.streamRatio_ * 2) + ratio) / 3 << ".\n" - << logofs_flush; - #endif - - proxyData_.streamRatio_ = ((proxyData_.streamRatio_ * 2) + ratio) / 3; - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! Updated compressed bytes " - << "with " << bytesIn << " in " << bytesOut << " out " - << "and ratio " << (double) proxyData_.streamRatio_ - << ".\n" << logofs_flush; - #endif -} - -// -// Recalculate the current bitrate. The bytes written -// are accounted at the time the transport actually -// writes the data to the network, not at the time it -// receives the data from the upper layers. The reason -// is that data can be compressed by the stream com- -// pressor, so we can become aware of the new bitrate -// only afer having flushed the ZLIB stream. This also -// means that, to have a reliable estimate, we need to -// flush the link often. -// - -void Statistics::updateBitrate(int bytes) -{ - T_timestamp thisFrameTs = getNewTimestamp(); - - int diffFramesInMs = diffTimestamp(startFrameTs_, thisFrameTs); - - #ifdef DEBUG - *logofs << "Statistics: Difference since previous timestamp is " - << diffFramesInMs << " Ms.\n" << logofs_flush; - #endif - - if (diffFramesInMs > 0) - { - #ifdef DEBUG - *logofs << "Statistics: Removing " << diffFramesInMs - << " Ms in short and long time frame.\n" - << logofs_flush; - #endif - - int shortBytesToRemove = (int) (((double) bytesInShortFrame_ * (double) diffFramesInMs) / - (double) control -> ShortBitrateTimeFrame); - - int longBytesToRemove = (int) (((double) bytesInLongFrame_ * (double) diffFramesInMs) / - (double) control -> LongBitrateTimeFrame); - - #ifdef DEBUG - *logofs << "Statistics: Removing " << shortBytesToRemove - << " bytes from " << bytesInShortFrame_ - << " in the short frame.\n" << logofs_flush; - #endif - - bytesInShortFrame_ -= shortBytesToRemove; - - if (bytesInShortFrame_ < 0) - { - #ifdef TEST - *logofs << "Statistics: Bytes in short frame are " - << bytesInShortFrame_ << ". Set to 0.\n" - << logofs_flush; - #endif - - bytesInShortFrame_ = 0; - } - - #ifdef DEBUG - *logofs << "Statistics: Removing " << longBytesToRemove - << " bytes from " << bytesInLongFrame_ - << " in the long frame.\n" << logofs_flush; - #endif - - bytesInLongFrame_ -= longBytesToRemove; - - if (bytesInLongFrame_ < 0) - { - #ifdef TEST - *logofs << "Statistics: Bytes in long frame are " - << bytesInLongFrame_ << ". Set to 0.\n" - << logofs_flush; - #endif - - bytesInLongFrame_ = 0; - } - - int diffStartInMs; - - diffStartInMs = diffTimestamp(thisFrameTs, startShortFrameTs_); - - if (diffStartInMs > control -> ShortBitrateTimeFrame) - { - addMsTimestamp(startShortFrameTs_, diffStartInMs); - } - - diffStartInMs = diffTimestamp(thisFrameTs, startLongFrameTs_); - - if (diffStartInMs > control -> LongBitrateTimeFrame) - { - addMsTimestamp(startLongFrameTs_, diffStartInMs); - } - - startFrameTs_ = thisFrameTs; - } - - #ifdef DEBUG - *logofs << "Statistics: Adding " << bytes << " bytes to " - << bytesInShortFrame_ << " in the short frame.\n" - << logofs_flush; - #endif - - bytesInShortFrame_ = bytesInShortFrame_ + bytes; - - #ifdef DEBUG - *logofs << "Statistics: Adding " << bytes << " bytes to " - << bytesInLongFrame_ << " in the long frame.\n" - << logofs_flush; - #endif - - bytesInLongFrame_ = bytesInLongFrame_ + bytes; - - bitrateInShortFrame_ = (int) ((double) bytesInShortFrame_ / - ((double) control -> ShortBitrateTimeFrame / 1000)); - - bitrateInLongFrame_ = (int) ((double) bytesInLongFrame_ / - ((double) control -> LongBitrateTimeFrame / 1000)); - - if (bitrateInShortFrame_ > topBitrate_) - { - topBitrate_ = bitrateInShortFrame_; - } - - #ifdef TEST - *logofs << "Statistics: Current bitrate is short " << bitrateInShortFrame_ - << " long " << bitrateInLongFrame_ << " top " << topBitrate_ - << ".\n" << logofs_flush; - #endif -} - -void Statistics::updateCongestion(int remaining, int limit) -{ - #ifdef TEST - *logofs << "Statistics: Updating the congestion " - << "counters at " << strMsTimestamp() - << ".\n" << logofs_flush; - #endif - - double current = remaining; - - if (current < 0) - { - current = 0; - } - - current = 9 * (limit - current) / limit; - - #ifdef TEST - *logofs << "Statistics: Current congestion is " - << current << " with " << limit << " tokens " - << "and " << remaining << " remaining.\n" - << logofs_flush; - #endif - - // - // If the current congestion counter is greater - // than the previous, take the current value, - // otherwise ramp down the value by calculating - // the average of the last 8 updates. - // - - #ifdef TEST - *logofs << "Statistics: Old congestion was " - << congestionInFrame_; - #endif - - if (current >= congestionInFrame_) - { - congestionInFrame_ = current; - } - else - { - congestionInFrame_ = ((congestionInFrame_ * 7) + current) / 8; - } - - #ifdef TEST - *logofs << " new congestion is " - << ((congestionInFrame_ * 7) + current) / 8 - << ".\n" << logofs_flush; - #endif - - // - // Call the function with 0 bytes flushed - // so the agent can update its congestion - // counter. - // - - FlushCallback(0); -} - -int Statistics::getClientCacheStats(int type, char *&buffer) -{ - if (type != PARTIAL_STATS && type != TOTAL_STATS) - { - #ifdef PANIC - *logofs << "Statistics: PANIC! Cannot produce statistics " - << "with qualifier '" << type << "'.\n" - << logofs_flush; - #endif - - return -1; - } - - // - // Print message cache data according - // to local and remote view. - // - - MessageStore *currentStore = NULL; - MessageStore *anyStore = NULL; - - char format[FORMAT_LENGTH]; - - strcat(buffer, "\nNX Cache Statistics\n"); - strcat(buffer, "-------------------\n\n"); - - for (int m = proxy_client; m <= proxy_server; m++) - { - if (m == proxy_client) - { - strcat(buffer, "Request\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n"); - strcat(buffer, "-------\t------\t--------------\t\t--------------\t\t-----------\n"); - } - else - { - strcat(buffer, "\nReply\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n"); - strcat(buffer, "-----\t------\t--------------\t\t--------------\t\t-----------\n"); - } - - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - if (m == proxy_client) - { - currentStore = proxy_ -> getClientStore() -> getRequestStore(i); - } - else - { - currentStore = proxy_ -> getServerStore() -> getReplyStore(i); - } - - if (currentStore != NULL && - (currentStore -> getLocalStorageSize() || - currentStore -> getRemoteStorageSize())) - { - anyStore = currentStore; - - sprintf(format, "#%d\t%d\t", i, currentStore -> getSize()); - - strcat(buffer, format); - - sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getLocalStorageSize(), - ((double) currentStore -> getLocalStorageSize()) / 1024); - - strcat(buffer, format); - - sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getRemoteStorageSize(), - ((double) currentStore -> getRemoteStorageSize()) / 1024); - - strcat(buffer, format); - - sprintf(format, "%d/%.0f KB\n", currentStore -> cacheSlots, - ((double) control -> getUpperStorageSize() / 100 * - currentStore -> cacheThreshold) / 1024); - - strcat(buffer, format); - } - } - - if (anyStore == NULL) - { - strcat(buffer, "N/A\n"); - } - } - - if (anyStore != NULL) - { - sprintf(format, "\ncache: %d bytes (%d KB) available at server.\n", - control -> ClientTotalStorageSize, - control -> ClientTotalStorageSize / 1024); - - strcat(buffer, format); - - sprintf(format, " %d bytes (%d KB) available at client.\n\n", - control -> ServerTotalStorageSize, - control -> ServerTotalStorageSize / 1024); - - strcat(buffer, format); - - sprintf(format, " %d bytes (%d KB) allocated at server.\n", - anyStore -> getLocalTotalStorageSize(), - anyStore -> getLocalTotalStorageSize() / 1024); - - strcat(buffer, format); - - sprintf(format, " %d bytes (%d KB) allocated at client.\n\n\n", - anyStore -> getRemoteTotalStorageSize(), - anyStore -> getRemoteTotalStorageSize() / 1024); - - strcat(buffer, format); - } - else - { - strcat(buffer, "\ncache: N/A\n\n"); - } - - return 1; -} - -int Statistics::getClientProtocolStats(int type, char *&buffer) -{ - if (type != PARTIAL_STATS && type != TOTAL_STATS) - { - #ifdef PANIC - *logofs << "Statistics: PANIC! Cannot produce statistics " - << "with qualifier '" << type << "'.\n" - << logofs_flush; - #endif - - return -1; - } - - struct T_transportData *transportData; - struct T_protocolData *protocolData; - struct T_overallData *overallData; - - if (type == PARTIAL_STATS) - { - transportData = &transportPartial_; - protocolData = &protocolPartial_; - overallData = &overallPartial_; - } - else - { - transportData = &transportTotal_; - protocolData = &protocolTotal_; - overallData = &overallTotal_; - } - - char format[FORMAT_LENGTH]; - - double countRequestIn = 0; - double countCachedRequestIn = 0; - double countRepliedRequestIn = 0; - - double countRequestBitsIn = 0; - double countRequestBitsOut = 0; - - double countAnyIn = 0; - double countBitsIn = 0; - double countBitsOut = 0; - - // - // Print request data. - // - - strcat(buffer, "NX Server Side Protocol Statistics\n"); - strcat(buffer, "----------------------------------\n\n"); - - // - // Print render data. - // - - strcat(buffer, "Render Total\tCached\tBits In\t\tBits Out\tBits/Request\t\tRatio\n"); - strcat(buffer, "------- -----\t------\t-------\t\t--------\t------------\t\t-----\n"); - - for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) - { - if (protocolData -> renderRequestCount_[i]) - { - sprintf(format, "#%d ", i); - - while (strlen(format) < 8) - { - strcat(format, " "); - } - - strcat(buffer, format); - - if (protocolData -> renderRequestCached_[i] > 0) - { - sprintf(format, "%.0f\t%.0f", protocolData -> renderRequestCount_[i], - protocolData -> renderRequestCached_[i]); - } - else - { - sprintf(format, "%.0f\t", protocolData -> renderRequestCount_[i]); - } - - strcat(buffer, format); - - sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", - protocolData -> renderRequestBitsIn_[i], protocolData -> renderRequestBitsIn_[i] / 8192, - protocolData -> renderRequestBitsOut_[i], protocolData -> renderRequestBitsOut_[i] / 8192, - protocolData -> renderRequestBitsIn_[i] / protocolData -> renderRequestCount_[i], - protocolData -> renderRequestBitsOut_[i] / protocolData -> renderRequestCount_[i]); - - strcat(buffer, format); - - if (protocolData -> renderRequestBitsOut_[i] > 0) - { - sprintf(format, "%5.3f:1\n", protocolData -> renderRequestBitsIn_[i] / - protocolData -> renderRequestBitsOut_[i]); - - strcat(buffer, format); - } - else - { - strcat(buffer, "1:1\n"); - } - } - - countRequestIn += protocolData -> renderRequestCount_[i]; - countCachedRequestIn += protocolData -> renderRequestCached_[i]; - - countRequestBitsIn += protocolData -> renderRequestBitsIn_[i]; - countRequestBitsOut += protocolData -> renderRequestBitsOut_[i]; - - countAnyIn += protocolData -> renderRequestCount_[i]; - countBitsIn += protocolData -> renderRequestBitsIn_[i]; - countBitsOut += protocolData -> renderRequestBitsOut_[i]; - } - - if (countRequestIn > 0) - { - if (countCachedRequestIn > 0) - { - sprintf(format, "\ntotal: %.0f\t%.0f", countRequestIn, countCachedRequestIn); - } - else - { - sprintf(format, "\ntotal: %.0f\t", countRequestIn); - } - - strcat(buffer, format); - - sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", - countRequestBitsIn, countRequestBitsIn / 8192, countRequestBitsOut, - countRequestBitsOut / 8192, countRequestBitsIn / countRequestIn, - countRequestBitsOut / countRequestIn); - - strcat(buffer, format); - - if (countRequestBitsOut > 0) - { - sprintf(format, "%5.3f:1\n", countRequestBitsIn / countRequestBitsOut); - } - else - { - sprintf(format, "1:1\n"); - } - - strcat(buffer, format); - } - else - { - strcat(buffer, "N/A\n\n"); - } - - countRequestIn = 0; - countCachedRequestIn = 0; - - countRequestBitsIn = 0; - countRequestBitsOut = 0; - - countAnyIn = 0; - countBitsIn = 0; - countBitsOut = 0; - - // - // Print other requests' data. - // - - strcat(buffer, "\nRequest Total\tCached\tBits In\t\tBits Out\tBits/Request\t\tRatio\n"); - strcat(buffer, "------- -----\t------\t-------\t\t--------\t------------\t\t-----\n"); - - for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) - { - if (protocolData -> requestCount_[i]) - { - sprintf(format, "#%d ", i); - - while (strlen(format) < 5) - { - strcat(format, " "); - } - - // - // Mark NX agent-related requests, those - // having a reply and finally those that - // have been probably tainted by client - // side. - // - - if (i >= X_NXFirstOpcode && i <= X_NXLastOpcode) - { - strcat(format, "A"); - } - - if (i != X_NXInternalGenericReply && protocolData -> requestReplied_[i] > 0) - { - strcat(format, "R"); - } - - if (i == X_NoOperation && control -> TaintReplies) - { - strcat(format, "T"); - } - - while (strlen(format) < 8) - { - strcat(format, " "); - } - - strcat(buffer, format); - - if (protocolData -> requestCached_[i] > 0) - { - sprintf(format, "%.0f\t%.0f", protocolData -> requestCount_[i], - protocolData -> requestCached_[i]); - } - else - { - sprintf(format, "%.0f\t", protocolData -> requestCount_[i]); - } - - strcat(buffer, format); - - sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", - protocolData -> requestBitsIn_[i], protocolData -> requestBitsIn_[i] / 8192, - protocolData -> requestBitsOut_[i], protocolData -> requestBitsOut_[i] / 8192, - protocolData -> requestBitsIn_[i] / protocolData -> requestCount_[i], - protocolData -> requestBitsOut_[i] / protocolData -> requestCount_[i]); - - strcat(buffer, format); - - if (protocolData -> requestBitsOut_[i] > 0) - { - sprintf(format, "%5.3f:1\n", protocolData -> requestBitsIn_[i] / - protocolData -> requestBitsOut_[i]); - - strcat(buffer, format); - } - else - { - strcat(buffer, "1:1\n"); - } - } - - countRequestIn += protocolData -> requestCount_[i]; - countCachedRequestIn += protocolData -> requestCached_[i]; - countRepliedRequestIn += protocolData -> requestReplied_[i]; - - countRequestBitsIn += protocolData -> requestBitsIn_[i]; - countRequestBitsOut += protocolData -> requestBitsOut_[i]; - - countAnyIn += protocolData -> requestCount_[i]; - countBitsIn += protocolData -> requestBitsIn_[i]; - countBitsOut += protocolData -> requestBitsOut_[i]; - } - - if (countRequestIn > 0) - { - if (countCachedRequestIn > 0) - { - sprintf(format, "\ntotal: %.0f\t%.0f", countRequestIn, countCachedRequestIn); - } - else - { - sprintf(format, "\ntotal: %.0f\t", countRequestIn); - } - - strcat(buffer, format); - - sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", - countRequestBitsIn, countRequestBitsIn / 8192, countRequestBitsOut, - countRequestBitsOut / 8192, countRequestBitsIn / countRequestIn, - countRequestBitsOut / countRequestIn); - - strcat(buffer, format); - - if (countRequestBitsOut > 0) - { - sprintf(format, "%5.3f:1\n", countRequestBitsIn / countRequestBitsOut); - } - else - { - sprintf(format, "1:1\n"); - } - - strcat(buffer, format); - } - else - { - strcat(buffer, "N/A\n\n"); - } - - // - // Print transport data. - // - - getTimeStats(type, buffer); - - countAnyIn += protocolData -> cupsCount_; - countBitsIn += protocolData -> cupsBitsIn_; - countBitsOut += protocolData -> cupsBitsOut_; - - countAnyIn += protocolData -> smbCount_; - countBitsIn += protocolData -> smbBitsIn_; - countBitsOut += protocolData -> smbBitsOut_; - - countAnyIn += protocolData -> mediaCount_; - countBitsIn += protocolData -> mediaBitsIn_; - countBitsOut += protocolData -> mediaBitsOut_; - - countAnyIn += protocolData -> httpCount_; - countBitsIn += protocolData -> httpBitsIn_; - countBitsOut += protocolData -> httpBitsOut_; - - countAnyIn += protocolData -> fontCount_; - countBitsIn += protocolData -> fontBitsIn_; - countBitsOut += protocolData -> fontBitsOut_; - - countAnyIn += protocolData -> slaveCount_; - countBitsIn += protocolData -> slaveBitsIn_; - countBitsOut += protocolData -> slaveBitsOut_; - - // - // Save the overall amount of bytes - // coming from X clients. - // - - overallData -> overallBytesIn_ = countBitsIn / 8; - - // - // Print performance data. - // - - if (transportData -> readTime_ > 0) - { - sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n", - countAnyIn / (transportData -> readTime_ / 1000), - (countBitsIn + transportData -> framingBitsOut_) / 8192 / - (transportData -> readTime_ / 1000)); - } - else - { - sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n", - countAnyIn, (countBitsIn + transportData -> - framingBitsOut_) / 8192); - } - - strcat(buffer, format); - - strcat(buffer, "link: "); - - // - // ZLIB compression stats. - // - - getStreamStats(type, buffer); - - // - // Save the overall amount of bytes - // sent on NX proxy link. - // - - if (transportData -> compressedBytesOut_ > 0) - { - overallData -> overallBytesOut_ = transportData -> compressedBytesOut_; - } - else - { - overallData -> overallBytesOut_ = countBitsOut / 8; - } - - // - // Print info on multiplexing overhead. - // - - getFramingStats(type, buffer); - - // - // Print stats about additional channels. - // - - getServicesStats(type, buffer); - - // - // Compression summary. - // - - double ratio = 1; - - if (transportData -> compressedBytesOut_ / 1024 > 0) - { - ratio = ((countBitsIn + transportData -> framingBitsOut_) / 8192) / - (transportData -> compressedBytesOut_ / 1024); - - } - else if (countBitsOut > 0) - { - ratio = (countBitsIn + transportData -> framingBitsOut_) / - countBitsOut; - } - - sprintf(format, " Protocol compression ratio is %5.3f:1.\n\n", - ratio); - - strcat(buffer, format); - - getBitrateStats(type, buffer); - - getSplitStats(type, buffer); - - sprintf(format, " %.0f total handled replies (%.0f unmatched).\n\n\n", - countRepliedRequestIn, protocolData -> requestReplied_[X_NXInternalGenericReply]); - - strcat(buffer, format); - - return 1; -} - -int Statistics::getClientOverallStats(int type, char *&buffer) -{ - if (type != PARTIAL_STATS && type != TOTAL_STATS) - { - #ifdef PANIC - *logofs << "Statistics: PANIC! Cannot produce statistics " - << "with qualifier '" << type << "'.\n" - << logofs_flush; - #endif - - return -1; - } - - struct T_overallData *overallData; - struct T_packedData *packedData; - - if (type == PARTIAL_STATS) - { - overallData = &overallPartial_; - packedData = &packedPartial_; - } - else - { - overallData = &overallTotal_; - packedData = &packedTotal_; - } - - char format[FORMAT_LENGTH]; - - // - // Print header including link type, - // followed by info on packed images. - // - - strcat(buffer, "NX Compression Summary\n"); - strcat(buffer, "----------------------\n\n"); - - char label[FORMAT_LENGTH]; - - switch (control -> LinkMode) - { - case LINK_TYPE_NONE: - { - strcpy(label, "NONE"); - - break; - } - case LINK_TYPE_MODEM: - { - strcpy(label, "MODEM"); - - break; - } - case LINK_TYPE_ISDN: - { - strcpy(label, "ISDN"); - - break; - } - case LINK_TYPE_ADSL: - { - strcpy(label, "ADSL"); - - break; - } - case LINK_TYPE_WAN: - { - strcpy(label, "WAN"); - - break; - } - case LINK_TYPE_LAN: - { - strcpy(label, "LAN"); - - break; - } - default: - { - strcpy(label, "Unknown"); - - break; - } - } - - sprintf(format, "link: %s", label); - - if (control -> LocalDeltaCompression == 1) - { - strcat(format, " with protocol compression enabled."); - } - else - { - strcat(format, " with protocol compression disabled."); - } - - strcat(format, "\n\n"); - - strcat(buffer, format); - - if (packedData -> packedBytesIn_ > 0) - { - sprintf(format, "images: %.0f bytes (%.0f KB) packed to %.0f (%.0f KB).\n\n", - packedData -> packedBytesOut_, packedData -> packedBytesOut_ / 1024, - packedData -> packedBytesIn_, packedData -> packedBytesIn_ / 1024); - - strcat(buffer, format); - - sprintf(format, " Images compression ratio is %5.3f:1.\n\n", - packedData -> packedBytesOut_ / packedData -> packedBytesIn_); - - strcat(buffer, format); - } - - double overallIn = overallData -> overallBytesIn_ - packedData -> packedBytesIn_ + - packedData -> packedBytesOut_; - - double overallOut = overallData -> overallBytesOut_; - - sprintf(format, "overall: %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", - overallIn, overallIn / 1024, overallOut, overallOut / 1024); - - strcat(buffer, format); - - if (overallData -> overallBytesOut_ > 0) - { - sprintf(format, " Overall NX server compression ratio is %5.3f:1.\n\n\n", - overallIn / overallOut); - } - else - { - sprintf(format, " Overall NX server compression ratio is 1:1.\n\n\n"); - } - - strcat(buffer, format); - - return 1; -} - -int Statistics::getServerCacheStats(int type, char *&buffer) -{ - if (type != PARTIAL_STATS && type != TOTAL_STATS) - { - #ifdef PANIC - *logofs << "Statistics: PANIC! Cannot produce statistics " - << "with qualifier '" << type << "'.\n" - << logofs_flush; - #endif - - return -1; - } - - // - // Print message cache data according - // to local and remote view. - // - - MessageStore *currentStore = NULL; - MessageStore *anyStore = NULL; - - char format[FORMAT_LENGTH]; - - strcat(buffer, "\nNX Cache Statistics\n"); - strcat(buffer, "-------------------\n\n"); - - for (int m = proxy_client; m <= proxy_server; m++) - { - if (m == proxy_client) - { - strcat(buffer, "Request\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n"); - strcat(buffer, "-------\t------\t--------------\t\t--------------\t\t-----------\n"); - } - else - { - strcat(buffer, "\nReply\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n"); - strcat(buffer, "-----\t------\t--------------\t\t--------------\t\t-----------\n"); - } - - for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) - { - if (m == proxy_client) - { - currentStore = proxy_ -> getClientStore() -> getRequestStore(i); - } - else - { - currentStore = proxy_ -> getServerStore() -> getReplyStore(i); - } - - if (currentStore != NULL && - (currentStore -> getLocalStorageSize() || - currentStore -> getRemoteStorageSize())) - { - anyStore = currentStore; - - sprintf(format, "#%d\t%d\t", i, currentStore -> getSize()); - - strcat(buffer, format); - - sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getRemoteStorageSize(), - ((double) currentStore -> getRemoteStorageSize()) / 1024); - - strcat(buffer, format); - - sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getLocalStorageSize(), - ((double) currentStore -> getLocalStorageSize()) / 1024); - - strcat(buffer, format); - - sprintf(format, "%d/%.0f KB\n", currentStore -> cacheSlots, - ((double) control -> getUpperStorageSize() / 100 * - currentStore -> cacheThreshold) / 1024); - - strcat(buffer, format); - } - } - - if (anyStore == NULL) - { - strcat(buffer, "N/A\n"); - } - } - - if (anyStore != NULL) - { - sprintf(format, "\ncache: %d bytes (%d KB) available at server.\n", - control -> ClientTotalStorageSize, - control -> ClientTotalStorageSize / 1024); - - strcat(buffer, format); - - sprintf(format, " %d bytes (%d KB) available at client.\n\n", - control -> ServerTotalStorageSize, - control -> ServerTotalStorageSize / 1024); - - strcat(buffer, format); - - sprintf(format, " %d bytes (%d KB) allocated at server.\n", - anyStore -> getRemoteTotalStorageSize(), - anyStore -> getRemoteTotalStorageSize() / 1024); - - strcat(buffer, format); - - sprintf(format, " %d bytes (%d KB) allocated at client.\n\n\n", - anyStore -> getLocalTotalStorageSize(), - anyStore -> getLocalTotalStorageSize() / 1024); - - strcat(buffer, format); - } - else - { - strcat(buffer, "\ncache: N/A\n\n"); - } - - return 1; -} - -int Statistics::getServerProtocolStats(int type, char *&buffer) -{ - if (type != PARTIAL_STATS && type != TOTAL_STATS) - { - #ifdef PANIC - *logofs << "Statistics: PANIC! Cannot produce statistics " - << "with qualifier '" << type << "'.\n" - << logofs_flush; - #endif - - return -1; - } - - struct T_transportData *transportData; - struct T_protocolData *protocolData; - struct T_overallData *overallData; - - if (type == PARTIAL_STATS) - { - transportData = &transportPartial_; - protocolData = &protocolPartial_; - overallData = &overallPartial_; - } - else - { - transportData = &transportTotal_; - protocolData = &protocolTotal_; - overallData = &overallTotal_; - } - - char format[FORMAT_LENGTH]; - - double countReplyBitsIn = 0; - double countReplyBitsOut = 0; - - double countReplyIn = 0; - double countCachedReplyIn = 0; - - double countEventBitsIn = 0; - double countEventBitsOut = 0; - - double countEventIn = 0; - double countCachedEventIn = 0; - - double countAnyIn = 0; - double countBitsIn = 0; - double countBitsOut = 0; - - // - // Print reply data. - // - - strcat(buffer, "NX Client Side Protocol Statistics\n"); - strcat(buffer, "----------------------------------\n\n"); - - strcat(buffer, "Reply Total\tCached\tBits In\t\tBits Out\tBits/Reply\t\tRatio\n"); - strcat(buffer, "------- -----\t------\t-------\t\t--------\t----------\t\t-----\n"); - - for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) - { - if (protocolData -> replyCount_[i]) - { - sprintf(format, "#%d ", i); - - while (strlen(format) < 5) - { - strcat(format, " "); - } - - // - // Mark replies originated - // by NX agent requests. - // - - if (i >= X_NXFirstOpcode && i <= X_NXLastOpcode) - { - strcat(format, "A"); - } - - // - // Mark replies that we didn't - // match against a request. - // - - if (i == 1) - { - strcat(format, "U"); - } - - while (strlen(format) < 8) - { - strcat(format, " "); - } - - strcat(buffer, format); - - if (protocolData -> replyCached_[i] > 0) - { - sprintf(format, "%.0f\t%.0f", protocolData -> replyCount_[i], - protocolData -> replyCached_[i]); - } - else - { - sprintf(format, "%.0f\t", protocolData -> replyCount_[i]); - } - - strcat(buffer, format); - - sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", - protocolData -> replyBitsIn_[i], protocolData -> replyBitsIn_[i] / 8192, - protocolData -> replyBitsOut_[i], protocolData -> replyBitsOut_[i] / 8192, - protocolData -> replyBitsIn_[i] / protocolData -> replyCount_[i], - protocolData -> replyBitsOut_[i] / protocolData -> replyCount_[i]); - - strcat(buffer, format); - - if (protocolData -> replyBitsOut_[i] > 0) - { - sprintf(format, "%5.3f:1\n", protocolData -> replyBitsIn_[i] / - protocolData -> replyBitsOut_[i]); - } - else - { - sprintf(format, "1:1\n"); - } - - strcat(buffer, format); - } - - countReplyIn += protocolData -> replyCount_[i]; - countCachedReplyIn += protocolData -> replyCached_[i]; - - countReplyBitsIn += protocolData -> replyBitsIn_[i]; - countReplyBitsOut += protocolData -> replyBitsOut_[i]; - - countAnyIn += protocolData -> replyCount_[i]; - countBitsIn += protocolData -> replyBitsIn_[i]; - countBitsOut += protocolData -> replyBitsOut_[i]; - } - - if (countReplyIn > 0) - { - if (countCachedReplyIn > 0) - { - sprintf(format, "\ntotal: %.0f\t%.0f", countReplyIn, countCachedReplyIn); - } - else - { - sprintf(format, "\ntotal: %.0f\t", countReplyIn); - } - - strcat(buffer, format); - - sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", - countReplyBitsIn, countReplyBitsIn / 8192, countReplyBitsOut, - countReplyBitsOut / 8192, countReplyBitsIn / countReplyIn, - countReplyBitsOut / countReplyIn); - - strcat(buffer, format); - - if (countReplyBitsOut > 0) - { - sprintf(format, "%5.3f:1\n", countReplyBitsIn / countReplyBitsOut); - } - else - { - sprintf(format, "1:1\n"); - } - - strcat(buffer, format); - } - else - { - strcat(buffer, "N/A\n"); - } - - strcat(buffer, "\n"); - - // - // Print event and error data. - // - - strcat(buffer, "Event Total\tCached\tBits In\t\tBits Out\tBits/Event\t\tRatio\n"); - strcat(buffer, "------- -----\t------\t-------\t\t--------\t----------\t\t-----\n"); - - for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) - { - if (protocolData -> eventCount_[i]) - { - sprintf(format, "#%d ", i); - - while (strlen(format) < 8) - { - strcat(format, " "); - } - - strcat(buffer, format); - - if (protocolData -> eventCached_[i] > 0) - { - sprintf(format, "%.0f\t%.0f", protocolData -> eventCount_[i], - protocolData -> eventCached_[i]); - } - else - { - sprintf(format, "%.0f\t", protocolData -> eventCount_[i]); - } - - strcat(buffer, format); - - sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", - protocolData -> eventBitsIn_[i], protocolData -> eventBitsIn_[i] / 8192, - protocolData -> eventBitsOut_[i], protocolData -> eventBitsOut_[i] / 8192, - protocolData -> eventBitsIn_[i] / protocolData -> eventCount_[i], - protocolData -> eventBitsOut_[i] / protocolData -> eventCount_[i]); - - strcat(buffer, format); - - if (protocolData -> eventBitsOut_[i] > 0) - { - sprintf(format, "%5.3f:1\n", protocolData -> eventBitsIn_[i] / - protocolData -> eventBitsOut_[i]); - } - else - { - sprintf(format, "1:1\n"); - } - - strcat(buffer, format); - } - - countEventIn += protocolData -> eventCount_[i]; - countCachedEventIn += protocolData -> eventCached_[i]; - - countEventBitsIn += protocolData -> eventBitsIn_[i]; - countEventBitsOut += protocolData -> eventBitsOut_[i]; - - countAnyIn += protocolData -> eventCount_[i]; - countBitsIn += protocolData -> eventBitsIn_[i]; - countBitsOut += protocolData -> eventBitsOut_[i]; - } - - if (countEventIn > 0) - { - if (countCachedEventIn > 0) - { - sprintf(format, "\ntotal: %.0f\t%.0f", countEventIn, countCachedEventIn); - } - else - { - sprintf(format, "\ntotal: %.0f\t", countEventIn); - } - - strcat(buffer, format); - - sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", - countEventBitsIn, countEventBitsIn / 8192, countEventBitsOut, - countEventBitsOut / 8192, countEventBitsIn / countEventIn, - countEventBitsOut / countEventIn); - - strcat(buffer, format); - - if (countEventBitsOut > 0) - { - sprintf(format, "%5.3f:1\n", countEventBitsIn / countEventBitsOut); - } - else - { - sprintf(format, "1:1\n"); - } - - strcat(buffer, format); - } - else - { - strcat(buffer, "N/A\n\n"); - } - - // - // Print transport data. - // - - getTimeStats(type, buffer); - - countAnyIn += protocolData -> cupsCount_; - countBitsIn += protocolData -> cupsBitsIn_; - countBitsOut += protocolData -> cupsBitsOut_; - - countAnyIn += protocolData -> smbCount_; - countBitsIn += protocolData -> smbBitsIn_; - countBitsOut += protocolData -> smbBitsOut_; - - countAnyIn += protocolData -> mediaCount_; - countBitsIn += protocolData -> mediaBitsIn_; - countBitsOut += protocolData -> mediaBitsOut_; - - countAnyIn += protocolData -> httpCount_; - countBitsIn += protocolData -> httpBitsIn_; - countBitsOut += protocolData -> httpBitsOut_; - - countAnyIn += protocolData -> fontCount_; - countBitsIn += protocolData -> fontBitsIn_; - countBitsOut += protocolData -> fontBitsOut_; - - countAnyIn += protocolData -> slaveCount_; - countBitsIn += protocolData -> slaveBitsIn_; - countBitsOut += protocolData -> slaveBitsOut_; - - // - // Save the overall amount of bytes - // coming from X clients. - // - - overallData -> overallBytesIn_ = countBitsIn / 8; - - // - // Print performance data. - // - - if (transportData -> readTime_ > 0) - { - sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n", - countAnyIn / (transportData -> readTime_ / 1000), - (countBitsIn + transportData -> framingBitsOut_) / 8192 / - (transportData -> readTime_ / 1000)); - } - else - { - sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n", - countAnyIn, (countBitsIn + transportData -> - framingBitsOut_) / 8192); - } - - strcat(buffer, format); - - strcat(buffer, "link: "); - - // - // ZLIB compression stats. - // - - getStreamStats(type, buffer); - - // - // Save the overall amount of bytes - // sent on NX proxy link. - // - - if (transportData -> compressedBytesOut_ > 0) - { - overallData -> overallBytesOut_ = transportData -> compressedBytesOut_; - } - else - { - overallData -> overallBytesOut_ = countBitsOut / 8; - } - - // - // Print info on multiplexing overhead. - // - - getFramingStats(type, buffer); - - // - // Print stats about additional channels. - // - - getServicesStats(type, buffer); - - // - // Compression summary. - // - - double ratio = 1; - - if (transportData -> compressedBytesOut_ / 1024 > 0) - { - ratio = ((countBitsIn + transportData -> framingBitsOut_) / 8192) / - (transportData -> compressedBytesOut_ / 1024); - - } - else if (countBitsOut > 0) - { - ratio = (countBitsIn + transportData -> framingBitsOut_) / - countBitsOut; - } - - sprintf(format, " Protocol compression ratio is %5.3f:1.\n\n", - ratio); - - strcat(buffer, format); - - getBitrateStats(type, buffer); - - // - // These are not included in output. - // - // getSplitStats(type, buffer); - // - - strcat(buffer, "\n"); - - // - // These statistics are not included in output. - // You can check it anyway to get the effective - // amount of bytes produced by unpack procedure. - // - // getClientOverallStats(type, buffer); - // - - return 1; -} - -int Statistics::getServerOverallStats(int type, char *&buffer) -{ - return 1; -} - -int Statistics::getTimeStats(int type, char *&buffer) -{ - struct T_transportData *transportData; - - if (type == PARTIAL_STATS) - { - transportData = &transportPartial_; - } - else - { - transportData = &transportTotal_; - } - - char format[FORMAT_LENGTH]; - - sprintf(format, "\ntime: %.0f Ms idle, %.0f Ms (%.0f Ms in read, %.0f Ms in write) running.\n\n", - transportData -> idleTime_, transportData -> readTime_, - transportData -> readTime_ - transportData -> writeTime_, - transportData -> writeTime_); - - strcat(buffer, format); - - return 1; -} - -int Statistics::getStreamStats(int type, char *&buffer) -{ - struct T_transportData *transportData; - - if (type == PARTIAL_STATS) - { - transportData = &transportPartial_; - } - else - { - transportData = &transportTotal_; - } - - char format[FORMAT_LENGTH]; - - if (transportData -> compressedBytesOut_ > 0) - { - sprintf(format, "%.0f bytes (%.0f KB) compressed to %.0f (%.0f KB).\n", - transportData -> compressedBytesIn_, transportData -> compressedBytesIn_ / 1024, - transportData -> compressedBytesOut_, transportData -> compressedBytesOut_ / 1024); - - strcat(buffer, format); - - sprintf(format, " %5.3f:1 stream compression ratio.\n\n", - transportData -> compressedBytesIn_ / transportData -> compressedBytesOut_); - - strcat(buffer, format); - } - - if (transportData -> decompressedBytesOut_ > 0) - { - if (transportData -> compressedBytesOut_ > 0) - { - strcat(buffer, " "); - } - - sprintf(format, "%.0f bytes (%.0f KB) decompressed to %.0f (%.0f KB).\n", - transportData -> decompressedBytesIn_, transportData -> decompressedBytesIn_ / 1024, - transportData -> decompressedBytesOut_, transportData -> decompressedBytesOut_ / 1024); - - strcat(buffer, format); - - sprintf(format, " %5.3f:1 stream compression ratio.\n\n", - transportData -> decompressedBytesOut_ / transportData -> decompressedBytesIn_); - - strcat(buffer, format); - } - - if (transportData -> compressedBytesOut_ > 0 || - transportData -> decompressedBytesOut_ > 0) - { - strcat(buffer, " "); - } - - return 1; -} - -int Statistics::getServicesStats(int type, char *&buffer) -{ - struct T_protocolData *protocolData; - - if (type == PARTIAL_STATS) - { - protocolData = &protocolPartial_; - } - else - { - protocolData = &protocolTotal_; - } - - char format[FORMAT_LENGTH]; - - if (protocolData -> cupsBitsOut_ > 0) - { - sprintf(format, " %.0f CUPS messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", - protocolData -> cupsCount_ , protocolData -> cupsBitsIn_ / 8, - protocolData -> cupsBitsIn_ / 8192, protocolData -> cupsBitsOut_ / 8, - protocolData -> cupsBitsOut_ / 8192); - - strcat(buffer, format); - } - - if (protocolData -> smbBitsOut_ > 0) - { - sprintf(format, " %.0f SMB messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", - protocolData -> smbCount_ , protocolData -> smbBitsIn_ / 8, - protocolData -> smbBitsIn_ / 8192, protocolData -> smbBitsOut_ / 8, - protocolData -> smbBitsOut_ / 8192); - - strcat(buffer, format); - } - - if (protocolData -> mediaBitsOut_ > 0) - { - sprintf(format, " %.0f multimedia messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", - protocolData -> mediaCount_ , protocolData -> mediaBitsIn_ / 8, - protocolData -> mediaBitsIn_ / 8192, protocolData -> mediaBitsOut_ / 8, - protocolData -> mediaBitsOut_ / 8192); - - strcat(buffer, format); - } - - if (protocolData -> httpBitsOut_ > 0) - { - sprintf(format, " %.0f HTTP messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", - protocolData -> httpCount_ , protocolData -> httpBitsIn_ / 8, - protocolData -> httpBitsIn_ / 8192, protocolData -> httpBitsOut_ / 8, - protocolData -> httpBitsOut_ / 8192); - - strcat(buffer, format); - } - - if (protocolData -> fontBitsOut_ > 0) - { - sprintf(format, " %.0f font server messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", - protocolData -> fontCount_ , protocolData -> fontBitsIn_ / 8, - protocolData -> fontBitsIn_ / 8192, protocolData -> fontBitsOut_ / 8, - protocolData -> fontBitsOut_ / 8192); - - strcat(buffer, format); - } - - if (protocolData -> slaveBitsOut_ > 0) - { - sprintf(format, " %.0f slave messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", - protocolData -> slaveCount_ , protocolData -> slaveBitsIn_ / 8, - protocolData -> slaveBitsIn_ / 8192, protocolData -> slaveBitsOut_ / 8, - protocolData -> slaveBitsOut_ / 8192); - - strcat(buffer, format); - } - - return 1; -} - -int Statistics::getFramingStats(int type, char *&buffer) -{ - struct T_transportData *transportData; - - if (type == PARTIAL_STATS) - { - transportData = &transportPartial_; - } - else - { - transportData = &transportTotal_; - } - - char format[FORMAT_LENGTH]; - - // - // Print info on multiplexing overhead. - // - - sprintf(format, "%.0f frames in, %.0f frames out, %.0f writes out.\n\n", - transportData -> proxyFramesIn_, transportData -> proxyFramesOut_, - transportData -> proxyWritesOut_); - - strcat(buffer, format); - - sprintf(format, " %.0f bytes (%.0f KB) used for framing and multiplexing.\n\n", - transportData -> framingBitsOut_ / 8, transportData -> framingBitsOut_ / 8192); - - strcat(buffer, format); - - return 1; -} - -int Statistics::getBitrateStats(int type, char *&buffer) -{ - struct T_transportData *transportData; - struct T_overallData *overallData; - - if (type == PARTIAL_STATS) - { - transportData = &transportPartial_; - overallData = &overallPartial_; - } - else - { - transportData = &transportTotal_; - overallData = &overallTotal_; - } - - double total = 0; - - if (transportData -> idleTime_ + transportData -> readTime_ > 0) - { - total = overallData -> overallBytesOut_ / - ((transportData -> idleTime_ + transportData -> readTime_) / 1000); - } - - char format[FORMAT_LENGTH]; - - sprintf(format, " %.0f B/s average, %d B/s %ds, %d B/s %ds, %d B/s maximum.\n\n", - total, getBitrateInShortFrame(), control -> ShortBitrateTimeFrame / 1000, - getBitrateInLongFrame(), control -> LongBitrateTimeFrame / 1000, - getTopBitrate()); - - strcat(buffer, format); - - resetTopBitrate(); - - return 1; -} - -int Statistics::getSplitStats(int type, char *&buffer) -{ - // - // Don't print these statistics if persistent - // cache of images is disabled. - // - - if (control -> ImageCacheEnableLoad == 0 && - control -> ImageCacheEnableSave == 0) - { - return 0; - } - - struct T_splitData *splitData; - - if (type == PARTIAL_STATS) - { - splitData = &splitPartial_; - } - else - { - splitData = &splitTotal_; - } - - char format[FORMAT_LENGTH]; - - // - // Print info on split messages restored from disk. - // - - sprintf(format, " %.0f images streamed, %.0f restored, %.0f bytes (%.0f KB) cached.\n\n", - splitData -> splitCount_, splitData -> splitAborted_, splitData -> splitAbortedBytesOut_, - splitData -> splitAbortedBytesOut_ / 1024); - - strcat(buffer, format); - - return 1; -} diff --git a/nxcomp/Statistics.h b/nxcomp/Statistics.h deleted file mode 100644 index 1ffb6b5d6..000000000 --- a/nxcomp/Statistics.h +++ /dev/null @@ -1,745 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Statistics_H -#define Statistics_H - -#include "NXproto.h" - -#include "Misc.h" -#include "Timestamp.h" - -class Proxy; - -// -// Opcode 255 is for generic requests, 1 is for -// generic replies (those which haven't a speci- -// fic differential encoding), opcode 0 is for -// generic messages from the auxiliary channels. -// - -#define STATISTICS_OPCODE_MAX 256 - -// -// Maximum length of the buffer allocated for -// the statistics output. -// - -#define STATISTICS_LENGTH 16384 - -// -// Query type. -// - -#define TOTAL_STATS 1 -#define PARTIAL_STATS 2 -#define NO_STATS 3 - -// -// Log level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Log the operations related to updating -// the control tokens. -// - -#undef TOKEN - -class Statistics -{ - public: - - // - // Use the proxy class to get access - // to the message stores. - // - - Statistics(Proxy *proxy); - - ~Statistics(); - - void addIdleTime(unsigned int numMs) - { - transportPartial_.idleTime_ += numMs; - transportTotal_.idleTime_ += numMs; - } - - void subIdleTime(unsigned int numMs) - { - transportPartial_.idleTime_ -= numMs; - transportTotal_.idleTime_ -= numMs; - } - - void addReadTime(unsigned int numMs) - { - transportPartial_.readTime_ += numMs; - transportTotal_.readTime_ += numMs; - } - - void subReadTime(unsigned int numMs) - { - transportPartial_.readTime_ -= numMs; - transportTotal_.readTime_ -= numMs; - } - - void addWriteTime(unsigned int numMs) - { - transportPartial_.writeTime_ += numMs; - transportTotal_.writeTime_ += numMs; - } - - void subWriteTime(unsigned int numMs) - { - transportPartial_.writeTime_ -= numMs; - transportTotal_.writeTime_ -= numMs; - } - - void addBytesIn(unsigned int numBytes) - { - transportPartial_.proxyBytesIn_ += numBytes; - transportTotal_.proxyBytesIn_ += numBytes; - } - - double getBytesIn() - { - return transportTotal_.proxyBytesIn_; - } - - void addBytesOut(unsigned int numBytes) - { - transportPartial_.proxyBytesOut_ += numBytes; - transportTotal_.proxyBytesOut_ += numBytes; - } - - double getBytesOut() - { - return transportTotal_.proxyBytesOut_; - } - - void addFrameIn() - { - transportPartial_.proxyFramesIn_++; - transportTotal_.proxyFramesIn_++; - - #ifdef TEST - *logofs << "Statistics: Updated total proxy frames in to " - << transportTotal_.proxyFramesIn_ << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - } - - void addFrameOut() - { - transportPartial_.proxyFramesOut_++; - transportTotal_.proxyFramesOut_++; - - #ifdef TEST - *logofs << "Statistics: Updated total proxy frames out to " - << transportTotal_.proxyFramesOut_ << " at " - << strMsTimestamp() << ".\n" - << logofs_flush; - #endif - } - - void addWriteOut() - { - transportPartial_.proxyWritesOut_++; - transportTotal_.proxyWritesOut_++; - - #ifdef TEST - *logofs << "Statistics: Updated total proxy writes out to " - << transportTotal_.proxyWritesOut_ << " at " - << strMsTimestamp() << ".\n" << logofs_flush; - #endif - } - - void addCompressedBytes(unsigned int bytesIn, unsigned int bytesOut); - - void addDecompressedBytes(unsigned int bytesIn, unsigned int bytesOut) - { - transportPartial_.decompressedBytesIn_ += bytesIn; - transportTotal_.decompressedBytesIn_ += bytesIn; - - transportPartial_.decompressedBytesOut_ += bytesOut; - transportTotal_.decompressedBytesOut_ += bytesOut; - } - - void addFramingBits(unsigned int bitsOut) - { - transportPartial_.framingBitsOut_ += bitsOut; - transportTotal_.framingBitsOut_ += bitsOut; - - proxyData_.protocolCount_ += bitsOut; - } - - void addCachedRequest(unsigned int opcode) - { - protocolPartial_.requestCached_[opcode]++; - protocolTotal_.requestCached_[opcode]++; - } - - void addRenderCachedRequest(unsigned int opcode) - { - protocolPartial_.renderRequestCached_[opcode]++; - protocolTotal_.renderRequestCached_[opcode]++; - } - - void addRepliedRequest(unsigned int opcode) - { - protocolPartial_.requestReplied_[opcode]++; - protocolTotal_.requestReplied_[opcode]++; - } - - void addCachedReply(unsigned int opcode) - { - protocolPartial_.replyCached_[opcode]++; - protocolTotal_.replyCached_[opcode]++; - } - - void addRequestBits(unsigned int opcode, unsigned int bitsIn, unsigned int bitsOut) - { - #ifdef DEBUG - *logofs << "Statistcs: Added " << bitsIn << " bits in and " - << bitsOut << " bits out to opcode " << opcode - << ".\n" << logofs_flush; - #endif - - protocolPartial_.requestCount_[opcode]++; - protocolTotal_.requestCount_[opcode]++; - - protocolPartial_.requestBitsIn_[opcode] += bitsIn; - protocolTotal_.requestBitsIn_[opcode] += bitsIn; - - protocolPartial_.requestBitsOut_[opcode] += bitsOut; - protocolTotal_.requestBitsOut_[opcode] += bitsOut; - - // - // Don't account the split bits - // to the control token. - // - - if (opcode != X_NXSplitData && opcode != X_NXSplitEvent) - { - proxyData_.protocolCount_ += bitsOut; - } - } - - void addRenderRequestBits(unsigned int opcode, unsigned int bitsIn, unsigned int bitsOut) - { - #ifdef DEBUG - *logofs << "Statistcs: Added " << bitsIn << " bits in and " - << bitsOut << " bits out to render opcode " << opcode - << ".\n" << logofs_flush; - #endif - - protocolPartial_.renderRequestCount_[opcode]++; - protocolTotal_.renderRequestCount_[opcode]++; - - protocolPartial_.renderRequestBitsIn_[opcode] += bitsIn; - protocolTotal_.renderRequestBitsIn_[opcode] += bitsIn; - - protocolPartial_.renderRequestBitsOut_[opcode] += bitsOut; - protocolTotal_.renderRequestBitsOut_[opcode] += bitsOut; - } - - void addReplyBits(unsigned int opcode, unsigned int bitsIn, unsigned int bitsOut) - { - protocolPartial_.replyCount_[opcode]++; - protocolTotal_.replyCount_[opcode]++; - - protocolPartial_.replyBitsIn_[opcode] += bitsIn; - protocolTotal_.replyBitsIn_[opcode] += bitsIn; - - protocolPartial_.replyBitsOut_[opcode] += bitsOut; - protocolTotal_.replyBitsOut_[opcode] += bitsOut; - - proxyData_.protocolCount_ += bitsOut; - } - - void addEventBits(unsigned int opcode, unsigned int bitsIn, unsigned int bitsOut) - { - protocolPartial_.eventCount_[opcode]++; - protocolTotal_.eventCount_[opcode]++; - - protocolPartial_.eventBitsIn_[opcode] += bitsIn; - protocolTotal_.eventBitsIn_[opcode] += bitsIn; - - protocolPartial_.eventBitsOut_[opcode] += bitsOut; - protocolTotal_.eventBitsOut_[opcode] += bitsOut; - - proxyData_.protocolCount_ += bitsOut; - } - - void addCupsBits(unsigned int bitsIn, unsigned int bitsOut) - { - protocolPartial_.cupsCount_++; - protocolTotal_.cupsCount_++; - - protocolPartial_.cupsBitsIn_ += bitsIn; - protocolTotal_.cupsBitsIn_ += bitsIn; - - protocolPartial_.cupsBitsOut_ += bitsOut; - protocolTotal_.cupsBitsOut_ += bitsOut; - } - - void addSmbBits(unsigned int bitsIn, unsigned int bitsOut) - { - protocolPartial_.smbCount_++; - protocolTotal_.smbCount_++; - - protocolPartial_.smbBitsIn_ += bitsIn; - protocolTotal_.smbBitsIn_ += bitsIn; - - protocolPartial_.smbBitsOut_ += bitsOut; - protocolTotal_.smbBitsOut_ += bitsOut; - } - - void addMediaBits(unsigned int bitsIn, unsigned int bitsOut) - { - protocolPartial_.mediaCount_++; - protocolTotal_.mediaCount_++; - - protocolPartial_.mediaBitsIn_ += bitsIn; - protocolTotal_.mediaBitsIn_ += bitsIn; - - protocolPartial_.mediaBitsOut_ += bitsOut; - protocolTotal_.mediaBitsOut_ += bitsOut; - } - - void addHttpBits(unsigned int bitsIn, unsigned int bitsOut) - { - protocolPartial_.httpCount_++; - protocolTotal_.httpCount_++; - - protocolPartial_.httpBitsIn_ += bitsIn; - protocolTotal_.httpBitsIn_ += bitsIn; - - protocolPartial_.httpBitsOut_ += bitsOut; - protocolTotal_.httpBitsOut_ += bitsOut; - } - - void addFontBits(unsigned int bitsIn, unsigned int bitsOut) - { - protocolPartial_.fontCount_++; - protocolTotal_.fontCount_++; - - protocolPartial_.fontBitsIn_ += bitsIn; - protocolTotal_.fontBitsIn_ += bitsIn; - - protocolPartial_.fontBitsOut_ += bitsOut; - protocolTotal_.fontBitsOut_ += bitsOut; - } - - void addSlaveBits(unsigned int bitsIn, unsigned int bitsOut) - { - protocolPartial_.slaveCount_++; - protocolTotal_.slaveCount_++; - - protocolPartial_.slaveBitsIn_ += bitsIn; - protocolTotal_.slaveBitsIn_ += bitsIn; - - protocolPartial_.slaveBitsOut_ += bitsOut; - protocolTotal_.slaveBitsOut_ += bitsOut; - } - - void addPackedBytesIn(unsigned int numBytes) - { - packedPartial_.packedBytesIn_ += numBytes; - packedTotal_.packedBytesIn_ += numBytes; - } - - void addPackedBytesOut(unsigned int numBytes) - { - packedPartial_.packedBytesOut_ += numBytes; - packedTotal_.packedBytesOut_ += numBytes; - } - - void addSplit() - { - splitPartial_.splitCount_++; - splitTotal_.splitCount_++; - } - - void addSplitAborted() - { - splitPartial_.splitAborted_++; - splitTotal_.splitAborted_++; - } - - void addSplitAbortedBytesOut(unsigned int numBytes) - { - splitPartial_.splitAbortedBytesOut_ += numBytes; - splitTotal_.splitAbortedBytesOut_ += numBytes; - } - - // - // Add the recorded protocol data to the proxy - // token counters. We want to send bpth the token - // request message and the data payload using a - // single system write, so we must guess how many - // output bytes we will generate. - // - - void updateControlToken(int &count) - { - // - // Total is the total number of protocol bytes - // generated so far. We have saved the number - // of bytes generated the last time the function - // was called so we can calculate the difference. - // - // The number of protocol bits is updated as soon - // as new bits are accumulated, to avoid summing - // up all the opcodes in this routine. We add a - // byte to the control bytes difference to account - // for the framing bits that are very likely to - // be added to the payload. - // - - double total = proxyData_.protocolCount_ / 8; - - double diff = total - proxyData_.controlCount_ + 1; - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! Protocol bytes are " - << total << " control bytes are " - << proxyData_.controlCount_ << " difference is " - << diff << ".\n" << logofs_flush; - #endif - - count += (int) (diff / proxyData_.streamRatio_); - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! Adding " - << (int) (diff / proxyData_.streamRatio_) - << " bytes to the control token with ratio " - << proxyData_.streamRatio_ << ".\n" - << logofs_flush; - #endif - - proxyData_.controlCount_ = total; - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! New control token has " - << count << " bytes with total control bytes " - << proxyData_.controlCount_ << ".\n" - << logofs_flush; - #endif - } - - void updateSplitToken(int &count) - { - double total = (protocolTotal_.requestBitsOut_[X_NXSplitData] + - protocolTotal_.eventBitsOut_[X_NXSplitEvent]) / 8; - - double diff = total - proxyData_.splitCount_; - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! Protocol bytes are " - << total << " split bytes are " - << proxyData_.splitCount_ << " difference is " - << diff << ".\n" << logofs_flush; - #endif - - count += (int) (diff / proxyData_.streamRatio_); - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! Adding " - << (int) (diff / proxyData_.streamRatio_) - << " bytes to the split token with ratio " - << proxyData_.streamRatio_ << ".\n" - << logofs_flush; - #endif - - proxyData_.splitCount_ = total; - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! New split token has " - << count << " bytes with total split bytes " - << proxyData_.splitCount_ << ".\n" - << logofs_flush; - #endif - } - - void updateDataToken(int &count) - { - double total = (protocolTotal_.cupsBitsOut_ + - protocolTotal_.smbBitsOut_ + - protocolTotal_.mediaBitsOut_ + - protocolTotal_.httpBitsOut_ + - protocolTotal_.fontBitsOut_ + - protocolTotal_.slaveBitsOut_) / 8; - - double diff = total - proxyData_.dataCount_; - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! Protocol bytes are " - << total << " data bytes are " - << proxyData_.dataCount_ << " difference is " - << diff << ".\n" << logofs_flush; - #endif - - count += (int) (diff / proxyData_.streamRatio_); - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! Adding " - << (int) (diff / proxyData_.streamRatio_) - << " bytes to the data token with ratio " - << proxyData_.streamRatio_ << ".\n" - << logofs_flush; - #endif - - proxyData_.dataCount_ = total; - - #if defined(TEST) || defined(TOKEN) - *logofs << "Statistics: TOKEN! New data token has " - << count << " bytes with total data bytes " - << proxyData_.dataCount_ << ".\n" - << logofs_flush; - #endif - } - - // - // Update the current bitrate. - // - - void updateBitrate(int bytes); - - // - // Return the current bitrate. - // - - int getBitrateInShortFrame() - { - return bitrateInShortFrame_; - } - - int getBitrateInLongFrame() - { - return bitrateInLongFrame_; - } - - int getTopBitrate() - { - return topBitrate_; - } - - void resetTopBitrate() - { - topBitrate_ = 0; - } - - double getStreamRatio() - { - return proxyData_.streamRatio_; - } - - // - // Manage the congestion level. - // - - void updateCongestion(int remaining, int limit); - - double getCongestionInFrame() - { - return congestionInFrame_; - } - - // - // Produce a dump of the statistics on - // the provided buffer. - // - - int getClientCacheStats(int type, char *&buffer); - int getClientProtocolStats(int type, char *&buffer); - int getClientOverallStats(int type, char *&buffer); - - int getServerCacheStats(int type, char *&buffer); - int getServerProtocolStats(int type, char *&buffer); - int getServerOverallStats(int type, char *&buffer); - - int resetPartialStats(); - - private: - - int getTimeStats(int type, char *&buffer); - int getServicesStats(int type, char *&buffer); - int getFramingStats(int type, char *&buffer); - int getBitrateStats(int type, char *&buffer); - int getStreamStats(int type, char *&buffer); - int getSplitStats(int type, char *&buffer); - - struct T_protocolData - { - double requestCached_[STATISTICS_OPCODE_MAX]; - double requestReplied_[STATISTICS_OPCODE_MAX]; - double requestCount_[STATISTICS_OPCODE_MAX]; - double requestBitsIn_[STATISTICS_OPCODE_MAX]; - double requestBitsOut_[STATISTICS_OPCODE_MAX]; - - double renderRequestCached_[STATISTICS_OPCODE_MAX]; - double renderRequestCount_[STATISTICS_OPCODE_MAX]; - double renderRequestBitsIn_[STATISTICS_OPCODE_MAX]; - double renderRequestBitsOut_[STATISTICS_OPCODE_MAX]; - - double replyCached_[STATISTICS_OPCODE_MAX]; - double replyCount_[STATISTICS_OPCODE_MAX]; - double replyBitsIn_[STATISTICS_OPCODE_MAX]; - double replyBitsOut_[STATISTICS_OPCODE_MAX]; - - double eventCached_[STATISTICS_OPCODE_MAX]; - double eventCount_[STATISTICS_OPCODE_MAX]; - double eventBitsIn_[STATISTICS_OPCODE_MAX]; - double eventBitsOut_[STATISTICS_OPCODE_MAX]; - - double cupsCount_; - double cupsBitsIn_; - double cupsBitsOut_; - - double smbCount_; - double smbBitsIn_; - double smbBitsOut_; - - double mediaCount_; - double mediaBitsIn_; - double mediaBitsOut_; - - double httpCount_; - double httpBitsIn_; - double httpBitsOut_; - - double fontCount_; - double fontBitsIn_; - double fontBitsOut_; - - double slaveCount_; - double slaveBitsIn_; - double slaveBitsOut_; - }; - - struct T_transportData - { - double idleTime_; - double readTime_; - double writeTime_; - - double proxyBytesIn_; - double proxyBytesOut_; - - double proxyFramesIn_; - double proxyFramesOut_; - double proxyWritesOut_; - - double compressedBytesIn_; - double compressedBytesOut_; - - double decompressedBytesIn_; - double decompressedBytesOut_; - - double framingBitsOut_; - }; - - struct T_packedData - { - double packedBytesIn_; - double packedBytesOut_; - }; - - struct T_splitData - { - double splitCount_; - double splitAborted_; - double splitAbortedBytesOut_; - }; - - struct T_overallData - { - double overallBytesIn_; - double overallBytesOut_; - }; - - struct T_proxyData - { - double protocolCount_; - double controlCount_; - double splitCount_; - double dataCount_; - - double streamRatio_; - }; - - T_protocolData protocolPartial_; - T_protocolData protocolTotal_; - - T_transportData transportPartial_; - T_transportData transportTotal_; - - T_packedData packedPartial_; - T_packedData packedTotal_; - - T_splitData splitPartial_; - T_splitData splitTotal_; - - T_overallData overallPartial_; - T_overallData overallTotal_; - - T_proxyData proxyData_; - - // - // Used to calculate the bandwidth usage - // of the proxy link. - // - - T_timestamp startShortFrameTs_; - T_timestamp startLongFrameTs_; - T_timestamp startFrameTs_; - - int bytesInShortFrame_; - int bytesInLongFrame_; - - int bitrateInShortFrame_; - int bitrateInLongFrame_; - - int topBitrate_; - - double congestionInFrame_; - - // - // Need the proxy pointer to print the - // statistics related to the client and - // server stores and to add the protocol - // data to the proxy token accumulators. - // - - Proxy *proxy_; -}; - -#endif /* Statistics_H */ diff --git a/nxcomp/Timestamp.cpp b/nxcomp/Timestamp.cpp deleted file mode 100644 index d5b3d613b..000000000 --- a/nxcomp/Timestamp.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Timestamp.h" - -// -// Log level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Last timestamp taken from the system. -// - -T_timestamp timestamp; - -// -// The following functions all use the ctime -// static buffer from the C library. -// - -char *strTimestamp(const T_timestamp &ts) -{ - char *ctime_now = ctime((time_t *) &ts.tv_sec); - - ctime_now[24] = '\0'; - - return ctime_now; -} - -// -// This is especially dirty. -// - -char *strMsTimestamp(const T_timestamp &ts) -{ - char *ctime_now = ctime((time_t *) &ts.tv_sec); - - char ctime_new[25]; - - sprintf(ctime_new, "%.8s:%3.3f", ctime_now + 11, - (float) ts.tv_usec / 1000); - - strncpy(ctime_now, ctime_new, 24); - - return ctime_now; -} diff --git a/nxcomp/Timestamp.h b/nxcomp/Timestamp.h deleted file mode 100644 index 604f5a3bc..000000000 --- a/nxcomp/Timestamp.h +++ /dev/null @@ -1,307 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Timestamp_H -#define Timestamp_H - -#include -#include -#include - -#include -#include - -#include "Misc.h" - -// -// Log level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// If not defined, always query the system time. -// - -#undef CACHE_TIMESTAMP - -// -// Log a warning if the time difference since -// the last update exceeds the given number -// of milliseconds. -// - -#define DRIFT_TIMESTAMP 1 - -// -// Type used for timeout manipulation. -// - -typedef struct timeval T_timestamp; - -// -// Last timestamp taken from the system. If the -// timestamp is cached, we need to explicitly -// get a new timestamp after any operation that -// may have required a relevant amount of time. -// - -extern T_timestamp timestamp; - -// -// Get a timestamp instance with values set -// at the given amount of milliseconds. -// - -inline T_timestamp getTimestamp(long ms) -{ - struct timeval ts; - - ts.tv_sec = ms / 1000; - ts.tv_usec = (ms % 1000) * 1000; - - return ts; -} - -// -// Return the difference in milliseconds -// between the two timestamps. -// - -inline long diffTimestamp(const T_timestamp &ts1, const T_timestamp &ts2) -{ - // - // Add 500 microseconds to round up - // to the nearest millisecond. - // - - return ((ts2.tv_sec * 1000 + (ts2.tv_usec + 500) / 1000) - - (ts1.tv_sec * 1000 + (ts1.tv_usec + 500) / 1000)); -} - -// -// The same in microseconds. It doesn't -// round the value. -// - -inline long diffUsTimestamp(const T_timestamp &ts1, const T_timestamp &ts2) -{ - return ((ts2.tv_sec * 1000000 + ts2.tv_usec) - - (ts1.tv_sec * 1000000 + ts1.tv_usec)); -} - -// -// Return the last timestamp taken from the -// system. It doesn't update the timestamp. -// - -inline T_timestamp getTimestamp() -{ - #ifdef CACHE_TIMESTAMP - - #ifdef TEST - - T_timestamp ts; - - gettimeofday(&ts, NULL); - - long diffTs = diffTimestamp(timestamp, ts); - - if (diffTs > DRIFT_TIMESTAMP) - { - *logofs << "Timestamp: WARNING! Time difference since the " - << "current timestamp is " << diffTs << " Ms.\n" - << logofs_flush; - } - - #endif - - return timestamp; - - #else - - gettimeofday(×tamp, NULL); - - return timestamp; - - #endif -} - -inline T_timestamp &setTimestamp(T_timestamp &ts, long ms) -{ - ts.tv_sec = ms / 1000; - ts.tv_usec = (ms % 1000) * 1000; - - return ts; -} - -// -// Return the smaller between two timestamps. -// - -inline T_timestamp &setMinTimestamp(T_timestamp &ts, long ms) -{ - if ((ts.tv_sec * 1000 + ts.tv_usec / 1000) > ms) - { - ts.tv_sec = ms / 1000; - ts.tv_usec = (ms % 1000) * 1000; - } - - return ts; -} - -inline T_timestamp &setMinTimestamp(T_timestamp &ts1, T_timestamp &ts2) -{ - if ((ts1.tv_sec * 1000000 + ts1.tv_usec) > - (ts2.tv_sec * 1000000 + ts2.tv_usec)) - { - ts1.tv_sec = ts2.tv_sec; - ts1.tv_usec = ts2.tv_usec; - } - - return ts1; -} - -// -// Convert a timestamp in the total number -// of milliseconds. -// - -inline long getMsTimestamp(const T_timestamp &ts) -{ - return ts.tv_sec * 1000 + ts.tv_usec / 1000; -} - -// -// A 0 value on both seconds and microseconds -// fields means that timestamp is invalid or -// not set. -// - -inline T_timestamp nullTimestamp() -{ - struct timeval ts; - - ts.tv_sec = 0; - ts.tv_usec = 0; - - return ts; -} - -inline bool isTimestamp(const T_timestamp &ts) -{ - if (ts.tv_sec == 0 && ts.tv_usec == 0) - { - return 0; - } - - return 1; -} - -inline void subMsTimestamp(T_timestamp &ts, long ms) -{ - ts.tv_sec -= ms / 1000; - ts.tv_usec -= (ms % 1000) * 1000; -} - -inline void addMsTimestamp(T_timestamp &ts, long ms) -{ - ts.tv_sec += ms / 1000; - ts.tv_usec += (ms % 1000) * 1000; -} - -// -// Check the difference between timestamps. -// Return 0 if the system time went backward -// compared to the second timestamp, or the -// difference between the timestamps exceeds -// the given number of milliseconds. -// - -inline int checkDiffTimestamp(const T_timestamp &ts1, const T_timestamp &ts2, - long ms = 30000) -{ - long diffTs = diffTimestamp(ts1, ts2); - - if (diffTs < 0 || diffTs > ms) - { - return 0; - } - - return 1; -} - -// -// Return a string representing the timestamp. -// - -char *strTimestamp(const T_timestamp &ts); -char *strMsTimestamp(const T_timestamp &ts); - -inline char *strTimestamp() -{ - return strTimestamp(getTimestamp()); -} - -inline char *strMsTimestamp() -{ - return strMsTimestamp(getTimestamp()); -} - -// -// Update the current timestamp. -// - -inline T_timestamp getNewTimestamp() -{ - #ifdef TEST - - T_timestamp ts; - - gettimeofday(&ts, NULL); - - *logofs << "Timestamp: Updating the current timestamp at " - << strMsTimestamp(ts) << ".\n" << logofs_flush; - - long diffTs = diffTimestamp(timestamp, ts); - - if (diffTs > DRIFT_TIMESTAMP) - { - *logofs << "Timestamp: WARNING! Time difference since the " - << "old timestamp is " << diffTs << " Ms.\n" - << logofs_flush; - } - - #endif - - gettimeofday(×tamp, NULL); - - return timestamp; -} - -#endif /* Timestamp_H */ diff --git a/nxcomp/TranslateCoords.cpp b/nxcomp/TranslateCoords.cpp deleted file mode 100644 index 97bd285e1..000000000 --- a/nxcomp/TranslateCoords.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "TranslateCoords.h" - -#include "ClientCache.h" - -#include "EncodeBuffer.h" -#include "DecodeBuffer.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Here are the methods to handle messages' content. -// - -int TranslateCoordsStore::parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - TranslateCoordsMessage *translateCoords = (TranslateCoordsMessage *) message; - - // - // Here is the fingerprint. - // - - translateCoords -> src_window = GetULONG(buffer + 4, bigEndian); - translateCoords -> dst_window = GetULONG(buffer + 8, bigEndian); - - translateCoords -> src_x = GetUINT(buffer + 12, bigEndian); - translateCoords -> src_y = GetUINT(buffer + 14, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -int TranslateCoordsStore::unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - TranslateCoordsMessage *translateCoords = (TranslateCoordsMessage *) message; - - // - // Fill all the message's fields. - // - - PutULONG(translateCoords -> src_window, buffer + 4, bigEndian); - PutULONG(translateCoords -> dst_window, buffer + 8, bigEndian); - - PutUINT(translateCoords -> src_x, buffer + 12, bigEndian); - PutUINT(translateCoords -> src_y, buffer + 14, bigEndian); - - #ifdef DEBUG - *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; - #endif - - return 1; -} - -void TranslateCoordsStore::dumpIdentity(const Message *message) const -{ - #ifdef DUMP - - TranslateCoordsMessage *translateCoords = (TranslateCoordsMessage *) message; - - *logofs << name() << ": Identity src_window " << translateCoords -> src_window << ", dst_window " - << translateCoords -> dst_window << ", src_x " << translateCoords -> src_x << ", src_y " - << translateCoords -> src_y << ", size " << translateCoords -> size_ << ".\n" << logofs_flush; - - #endif -} - -void TranslateCoordsStore::identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const -{ - md5_append(md5_state_, buffer + 4, 4); - md5_append(md5_state_, buffer + 8, 4); - md5_append(md5_state_, buffer + 12, 2); - md5_append(md5_state_, buffer + 14, 2); -} diff --git a/nxcomp/TranslateCoords.h b/nxcomp/TranslateCoords.h deleted file mode 100644 index 997d079e1..000000000 --- a/nxcomp/TranslateCoords.h +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef TranslateCoords_H -#define TranslateCoords_H - -#include "Message.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef DUMP - -// -// Set default values. -// - -#define TRANSLATECOORDS_ENABLE_CACHE 1 -#define TRANSLATECOORDS_ENABLE_DATA 0 -#define TRANSLATECOORDS_ENABLE_SPLIT 0 -#define TRANSLATECOORDS_ENABLE_COMPRESS 0 - -#define TRANSLATECOORDS_DATA_LIMIT 0 -#define TRANSLATECOORDS_DATA_OFFSET 16 - -#define TRANSLATECOORDS_CACHE_SLOTS 3000 -#define TRANSLATECOORDS_CACHE_THRESHOLD 3 -#define TRANSLATECOORDS_CACHE_LOWER_THRESHOLD 1 - -// -// The message class. -// - -class TranslateCoordsMessage : public Message -{ - friend class TranslateCoordsStore; - - public: - - TranslateCoordsMessage() - { - } - - ~TranslateCoordsMessage() - { - } - - // - // Put here the fields which constitute - // the 'identity' part of the message. - // - - private: - - unsigned int src_window; - unsigned int dst_window; - unsigned int src_x; - unsigned int src_y; - - unsigned char r_same_screen; - unsigned int r_child_window; - unsigned int r_dst_x; - unsigned int r_dst_y; -}; - -class TranslateCoordsStore : public MessageStore -{ - // - // Constructors and destructors. - // - - public: - - TranslateCoordsStore() : MessageStore() - { - enableCache = TRANSLATECOORDS_ENABLE_CACHE; - enableData = TRANSLATECOORDS_ENABLE_DATA; - enableSplit = TRANSLATECOORDS_ENABLE_SPLIT; - enableCompress = TRANSLATECOORDS_ENABLE_COMPRESS; - - dataLimit = TRANSLATECOORDS_DATA_LIMIT; - dataOffset = TRANSLATECOORDS_DATA_OFFSET; - - cacheSlots = TRANSLATECOORDS_CACHE_SLOTS; - cacheThreshold = TRANSLATECOORDS_CACHE_THRESHOLD; - cacheLowerThreshold = TRANSLATECOORDS_CACHE_LOWER_THRESHOLD; - - messages_ -> resize(cacheSlots); - - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - *i = NULL; - } - - temporary_ = NULL; - } - - virtual ~TranslateCoordsStore() - { - for (T_messages::iterator i = messages_ -> begin(); - i < messages_ -> end(); i++) - { - destroy(*i); - } - - destroy(temporary_); - } - - virtual const char *name() const - { - return "TranslateCoords"; - } - - virtual unsigned char opcode() const - { - return X_TranslateCoords; - } - - virtual unsigned int storage() const - { - return sizeof(TranslateCoordsMessage); - } - - // - // Message handling methods. - // - - public: - - virtual Message *create() const - { - return new TranslateCoordsMessage(); - } - - virtual Message *create(const Message &message) const - { - return new TranslateCoordsMessage((const TranslateCoordsMessage &) message); - } - - virtual void destroy(Message *message) const - { - delete (TranslateCoordsMessage *) message; - } - - virtual int parseIdentity(Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual int unparseIdentity(const Message *message, unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void identityChecksum(const Message *message, const unsigned char *buffer, - unsigned int size, int bigEndian) const; - - virtual void dumpIdentity(const Message *message) const; -}; - -#endif /* TranslateCoords_H */ diff --git a/nxcomp/Transport.cpp b/nxcomp/Transport.cpp deleted file mode 100644 index eaf9775af..000000000 --- a/nxcomp/Transport.cpp +++ /dev/null @@ -1,3064 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include -#include - -#include "Transport.h" - -#include "Statistics.h" - -// -// Set the verbosity level. You also -// need to define DUMP in Misc.cpp -// if DUMP is defined here. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG -#undef INSPECT -#undef DUMP - -// -// Used to lock and unlock the transport -// buffers before they are accessed by -// different threads. -// - -#undef THREADS - -// -// Define this to get logging all the -// operations performed by the parent -// thread, the one that enqueues and -// dequeues data. -// - -#define PARENT - -// -// Define this to know when a channel -// is created or destroyed. -// - -#undef REFERENCES - -// -// Reference count for allocated buffers. -// - -#ifdef REFERENCES - -int Transport::references_; -int ProxyTransport::references_; -int InternalTransport::references_; - -#endif - -// -// This is the base class providing methods for read -// and write buffering. -// - -Transport::Transport(int fd) : fd_(fd) -{ - #ifdef TEST - *logofs << "Transport: Going to create base transport " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - type_ = transport_base; - - // - // Set up the write buffer. - // - - w_buffer_.length_ = 0; - w_buffer_.start_ = 0; - - initialSize_ = TRANSPORT_BUFFER_DEFAULT_SIZE; - thresholdSize_ = TRANSPORT_BUFFER_DEFAULT_SIZE << 1; - maximumSize_ = TRANSPORT_BUFFER_DEFAULT_SIZE << 4; - - w_buffer_.data_.resize(initialSize_); - - // - // Set non-blocking IO on socket. - // - - SetNonBlocking(fd_, 1); - - blocked_ = 0; - finish_ = 0; - - #ifdef REFERENCES - *logofs << "Transport: Created new object at " - << this << " out of " << ++references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -Transport::~Transport() -{ - #ifdef TEST - *logofs << "Transport: Going to destroy base class " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - ::close(fd_); - - #ifdef REFERENCES - *logofs << "Transport: Deleted object at " - << this << " out of " << --references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -// -// Read data from its file descriptor. -// - -int Transport::read(unsigned char *data, unsigned int size) -{ - #ifdef DEBUG - *logofs << "Transport: Going to read " << size << " bytes from " - << "FD#" << fd_ << ".\n" << logofs_flush; - #endif - - // - // Read the available data from the socket. - // - - int result = ::read(fd_, data, size); - - // - // Update the current timestamp as the read - // can have scheduled some other process. - // - - getNewTimestamp(); - - if (result < 0) - { - if (EGET() == EAGAIN) - { - #ifdef TEST - *logofs << "Transport: WARNING! Read of " << size << " bytes from " - << "FD#" << fd_ << " would block.\n" << logofs_flush; - #endif - - return 0; - } - else if (EGET() == EINTR) - { - #ifdef TEST - *logofs << "Transport: Read of " << size << " bytes from " - << "FD#" << fd_ << " was interrupted.\n" - << logofs_flush; - #endif - - return 0; - } - else - { - #ifdef TEST - *logofs << "Transport: Error reading from " - << "FD#" << fd_ << ".\n" << logofs_flush; - #endif - - finish(); - - return -1; - } - } - else if (result == 0) - { - #ifdef TEST - *logofs << "Transport: No data read from " - << "FD#" << fd_ << ".\n" << logofs_flush; - #endif - - finish(); - - return -1; - } - - #ifdef TEST - *logofs << "Transport: Read " << result << " bytes out of " - << size << " from FD#" << fd_ << ".\n" << logofs_flush; - #endif - - #ifdef DUMP - - *logofs << "Transport: Dumping content of read data.\n" - << logofs_flush; - - DumpData(data, result); - - #endif - - return result; -} - -// -// Write as many bytes as possible to socket. -// Append the remaining data bytes to the end -// of the buffer and update length to reflect -// changes. -// - -int Transport::write(T_write type, const unsigned char *data, const unsigned int size) -{ - // - // If an immediate write was requested then - // flush the enqueued data first. - // - // Alternatively may try to write only if - // the socket is not blocked. - // - // if (w_buffer_.length_ > 0 && blocked_ == 0 && - // type == write_immediate) - // { - // ... - // } - // - - if (w_buffer_.length_ > 0 && type == write_immediate) - - { - #ifdef TEST - *logofs << "Transport: Writing " << w_buffer_.length_ - << " bytes of previous data to FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - int result = Transport::flush(); - - if (result < 0) - { - return -1; - } - } - - // - // If nothing is remained, write immediately - // to the socket. - // - - unsigned int written = 0; - - if (w_buffer_.length_ == 0 && blocked_ == 0 && - type == write_immediate) - { - // - // Limit the amount of data sent. - // - - unsigned int toWrite = size; - - #ifdef DUMP - - *logofs << "Transport: Going to write " << toWrite - << " bytes to FD#" << fd_ << " with checksum "; - - DumpChecksum(data, size); - - *logofs << ".\n" << logofs_flush; - - #endif - - T_timestamp writeTs; - - int diffTs; - - while (written < toWrite) - { - // - // Trace system time spent writing data. - // - - writeTs = getTimestamp(); - - int result = ::write(fd_, data + written, toWrite - written); - - diffTs = diffTimestamp(writeTs, getNewTimestamp()); - - statistics -> addWriteTime(diffTs); - - if (result <= 0) - { - if (EGET() == EAGAIN) - { - #ifdef TEST - *logofs << "Transport: Write of " << toWrite - written - << " bytes on FD#" << fd_ << " would block.\n" - << logofs_flush; - #endif - - blocked_ = 1; - - break; - } - else if (EGET() == EINTR) - { - #ifdef TEST - *logofs << "Transport: Write of " << toWrite - written - << " bytes on FD#" << fd_ << " was interrupted.\n" - << logofs_flush; - #endif - - continue; - } - else - { - #ifdef TEST - *logofs << "Transport: Write to " << "FD#" - << fd_ << " failed.\n" << logofs_flush; - #endif - - finish(); - - return -1; - } - } - else - { - #ifdef TEST - *logofs << "Transport: Immediately written " << result - << " bytes on " << "FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - written += result; - } - } - - #ifdef DUMP - - if (written > 0) - { - *logofs << "Transport: Dumping content of immediately written data.\n" - << logofs_flush; - - DumpData(data, written); - } - - #endif - } - - if (written == size) - { - // - // We will not affect the write buffer. - // - - return written; - } - - #ifdef DEBUG - *logofs << "Transport: Going to append " << size - written - << " bytes to write buffer for " << "FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - if (resize(w_buffer_, size - written) < 0) - { - return -1; - } - - memmove(w_buffer_.data_.begin() + w_buffer_.start_ + w_buffer_.length_, - data + written, size - written); - - w_buffer_.length_ += size - written; - - #ifdef TEST - *logofs << "Transport: Write buffer for FD#" << fd_ - << " has data for " << w_buffer_.length_ << " bytes.\n" - << logofs_flush; - - *logofs << "Transport: Start is " << w_buffer_.start_ - << " length is " << w_buffer_.length_ << " size is " - << w_buffer_.data_.size() << " capacity is " - << w_buffer_.data_.capacity() << ".\n" - << logofs_flush; - #endif - - // - // Note that this function always returns the whole - // size of buffer that was provided, either if not - // all the data could be actually written. - // - - return size; -} - -// -// Write pending data to its file descriptor. -// - -int Transport::flush() -{ - if (w_buffer_.length_ == 0) - { - #ifdef TEST - *logofs << "Transport: No data to flush on " - << "FD#" << fd_ << ".\n" << logofs_flush; - #endif - - #ifdef WARNING - if (blocked_ != 0) - { - *logofs << "Transport: Blocked flag is " << blocked_ - << " with no data to flush on FD#" << fd_ - << ".\n" << logofs_flush; - } - #endif - - return 0; - } - - // - // It's time to move data from the - // write buffer to the real link. - // - - int written = 0; - - int toWrite = w_buffer_.length_; - - // - // We will do our best to write any available - // data to the socket, so let's say we start - // from a clean state. - // - - blocked_ = 0; - - #ifdef TEST - *logofs << "Transport: Going to flush " << toWrite - << " bytes on FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - T_timestamp writeTs; - - int diffTs; - - while (written < toWrite) - { - writeTs = getTimestamp(); - - int result = ::write(fd_, w_buffer_.data_.begin() + w_buffer_.start_ + - written, toWrite - written); - - diffTs = diffTimestamp(writeTs, getNewTimestamp()); - - statistics -> addWriteTime(diffTs); - - if (result <= 0) - { - if (EGET() == EAGAIN) - { - #ifdef TEST - *logofs << "Transport: Write of " << toWrite - written - << " bytes on FD#" << fd_ << " would block.\n" - << logofs_flush; - #endif - - blocked_ = 1; - - break; - } - else if (EGET() == EINTR) - { - #ifdef TEST - *logofs << "Transport: Write of " << toWrite - written - << " bytes on FD#" << fd_ << " was interrupted.\n" - << logofs_flush; - #endif - - continue; - } - else - { - #ifdef TEST - *logofs << "Transport: Write to " << "FD#" - << fd_ << " failed.\n" << logofs_flush; - #endif - - finish(); - - return -1; - } - } - else - { - #ifdef TEST - *logofs << "Transport: Flushed " << result << " bytes on " - << "FD#" << fd_ << ".\n" << logofs_flush; - #endif - - written += result; - } - } - - if (written > 0) - { - #ifdef DUMP - - *logofs << "Transport: Dumping content of flushed data.\n" - << logofs_flush; - - DumpData(w_buffer_.data_.begin() + w_buffer_.start_, written); - - #endif - - // - // Update the buffer status. - // - - w_buffer_.length_ -= written; - - if (w_buffer_.length_ == 0) - { - w_buffer_.start_ = 0; - } - else - { - w_buffer_.start_ += written; - } - } - - // - // It can be that we wrote less bytes than - // available because of the write limit. - // - - if (w_buffer_.length_ > 0) - { - #ifdef TEST - *logofs << "Transport: There are still " << w_buffer_.length_ - << " bytes in write buffer for " << "FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - blocked_ = 1; - } - - #ifdef TEST - *logofs << "Transport: Write buffer for FD#" << fd_ - << " has data for " << w_buffer_.length_ << " bytes.\n" - << logofs_flush; - - *logofs << "Transport: Start is " << w_buffer_.start_ - << " length is " << w_buffer_.length_ << " size is " - << w_buffer_.data_.size() << " capacity is " - << w_buffer_.data_.capacity() << ".\n" - << logofs_flush; - #endif - - // - // No new data was produced for the link except - // any outstanding data from previous writes. - // - - return 0; -} - -int Transport::drain(int limit, int timeout) -{ - if (w_buffer_.length_ <= limit) - { - return 1; - } - - // - // Write the data accumulated in the write - // buffer until it is below the limit or - // the timeout is elapsed. - // - - int toWrite = w_buffer_.length_; - - int written = 0; - - #ifdef TEST - *logofs << "Transport: Draining " << toWrite - limit - << " bytes on FD#" << fd_ << " with limit set to " - << limit << ".\n" << logofs_flush; - #endif - - T_timestamp startTs = getNewTimestamp(); - - T_timestamp selectTs; - T_timestamp writeTs; - T_timestamp idleTs; - - T_timestamp nowTs = startTs; - - int diffTs; - - fd_set writeSet; - fd_set readSet; - - FD_ZERO(&writeSet); - FD_ZERO(&readSet); - - int result; - int ready; - - while (w_buffer_.length_ - written > limit) - { - nowTs = getNewTimestamp(); - - // - // Wait for descriptor to become - // readable or writable. - // - - FD_SET(fd_, &writeSet); - FD_SET(fd_, &readSet); - - setTimestamp(selectTs, timeout / 2); - - idleTs = nowTs; - - result = select(fd_ + 1, &readSet, &writeSet, NULL, &selectTs); - - nowTs = getNewTimestamp(); - - diffTs = diffTimestamp(idleTs, nowTs); - - statistics -> addIdleTime(diffTs); - - statistics -> subReadTime(diffTs); - - if (result < 0) - { - if (EGET() == EINTR) - { - #ifdef TEST - *logofs << "Transport: Select on FD#" << fd_ - << " was interrupted.\n" << logofs_flush; - #endif - - continue; - } - else - { - #ifdef TEST - *logofs << "Transport: Select on FD#" << fd_ - << " failed.\n" << logofs_flush; - #endif - - finish(); - - return -1; - } - } - else if (result > 0) - { - ready = result; - - if (FD_ISSET(fd_, &writeSet)) - { - writeTs = getNewTimestamp(); - - result = ::write(fd_, w_buffer_.data_.begin() + w_buffer_.start_ + - written, toWrite - written); - - nowTs = getNewTimestamp(); - - diffTs = diffTimestamp(writeTs, nowTs); - - statistics -> addWriteTime(diffTs); - - if (result > 0) - { - #ifdef TEST - *logofs << "Transport: Forced flush of " << result - << " bytes on " << "FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - written += result; - } - else if (result < 0 && EGET() == EINTR) - { - #ifdef TEST - *logofs << "Transport: Write to FD#" << fd_ - << " was interrupted.\n" << logofs_flush; - #endif - - continue; - } - else - { - #ifdef TEST - *logofs << "Transport: Write to FD#" << fd_ - << " failed.\n" << logofs_flush; - #endif - - finish(); - - return -1; - } - - ready--; - } - - if (ready > 0) - { - if (FD_ISSET(fd_, &readSet)) - { - #ifdef TEST - *logofs << "Transport: Not draining further " - << "due to data readable on FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - break; - } - } - } - #ifdef TEST - else - { - *logofs << "Transport: Timeout encountered " - << "waiting for FD#" << fd_ << ".\n" - << logofs_flush; - } - #endif - - nowTs = getNewTimestamp(); - - diffTs = diffTimestamp(startTs, nowTs); - - if (diffTs >= timeout) - { - #ifdef TEST - *logofs << "Transport: Not draining further " - << "due to the timeout on FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - break; - } - } - - if (written > 0) - { - #ifdef DUMP - - *logofs << "Transport: Dumping content of flushed data.\n" - << logofs_flush; - - DumpData(w_buffer_.data_.begin() + w_buffer_.start_, written); - - #endif - - // - // Update the buffer status. - // - - w_buffer_.length_ -= written; - - if (w_buffer_.length_ == 0) - { - w_buffer_.start_ = 0; - - blocked_ = 0; - } - else - { - w_buffer_.start_ += written; - - #ifdef TEST - *logofs << "Transport: There are still " << w_buffer_.length_ - << " bytes in write buffer for " << "FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - blocked_ = 1; - } - } - #ifdef TEST - else - { - *logofs << "Transport: WARNING! No data written to FD#" << fd_ - << " with " << toWrite << " bytes to drain and limit " - << "set to " << limit << ".\n" << logofs_flush; - } - #endif - - #ifdef TEST - *logofs << "Transport: Write buffer for FD#" << fd_ - << " has data for " << w_buffer_.length_ << " bytes.\n" - << logofs_flush; - - *logofs << "Transport: Start is " << w_buffer_.start_ - << " length is " << w_buffer_.length_ << " size is " - << w_buffer_.data_.size() << " capacity is " - << w_buffer_.data_.capacity() << ".\n" - << logofs_flush; - #endif - - return (w_buffer_.length_ <= limit); -} - -int Transport::wait(int timeout) const -{ - T_timestamp startTs = getNewTimestamp(); - - T_timestamp idleTs; - T_timestamp selectTs; - - T_timestamp nowTs = startTs; - - long available = 0; - int result = 0; - - int diffTs; - - fd_set readSet; - - FD_ZERO(&readSet); - FD_SET(fd_, &readSet); - - for (;;) - { - available = readable(); - - diffTs = diffTimestamp(startTs, nowTs); - - if (available != 0 || timeout == 0 || - (diffTs + (timeout / 10)) >= timeout) - { - #ifdef TEST - *logofs << "Transport: There are " << available - << " bytes on FD#" << fd_ << " after " - << diffTs << " Ms.\n" << logofs_flush; - #endif - - return available; - } - else if (available == 0 && result > 0) - { - #ifdef TEST - *logofs << "Transport: Read on " << "FD#" - << fd_ << " failed.\n" << logofs_flush; - #endif - - return -1; - } - - // - // TODO: Should subtract the time - // already spent in select. - // - - selectTs.tv_sec = 0; - selectTs.tv_usec = timeout * 1000; - - idleTs = nowTs; - - // - // Wait for descriptor to become readable. - // - - result = select(fd_ + 1, &readSet, NULL, NULL, &selectTs); - - nowTs = getNewTimestamp(); - - diffTs = diffTimestamp(idleTs, nowTs); - - statistics -> addIdleTime(diffTs); - - statistics -> subReadTime(diffTs); - - if (result < 0) - { - if (EGET() == EINTR) - { - #ifdef TEST - *logofs << "Transport: Select on FD#" << fd_ - << " was interrupted.\n" << logofs_flush; - #endif - - continue; - } - else - { - #ifdef TEST - *logofs << "Transport: Select on " << "FD#" - << fd_ << " failed.\n" << logofs_flush; - #endif - - return -1; - } - } - #ifdef TEST - else if (result == 0) - { - *logofs << "Transport: No data available on FD#" << fd_ - << " after " << diffTimestamp(startTs, nowTs) - << " Ms.\n" << logofs_flush; - } - else - { - *logofs << "Transport: Data became available on FD#" << fd_ - << " after " << diffTimestamp(startTs, nowTs) - << " Ms.\n" << logofs_flush; - } - #endif - } -} - -void Transport::setSize(unsigned int initialSize, unsigned int thresholdSize, - unsigned int maximumSize) -{ - initialSize_ = initialSize; - thresholdSize_ = thresholdSize; - maximumSize_ = maximumSize; - - #ifdef TEST - *logofs << "Transport: Set buffer sizes for FD#" << fd_ - << " to " << initialSize_ << "/" << thresholdSize_ - << "/" << maximumSize_ << ".\n" << logofs_flush; - #endif -} - -void Transport::fullReset() -{ - blocked_ = 0; - finish_ = 0; - - fullReset(w_buffer_); -} - -int Transport::resize(T_buffer &buffer, const int &size) -{ - if ((int) buffer.data_.size() >= (buffer.length_ + size) && - (buffer.start_ + buffer.length_ + size) > - (int) buffer.data_.size()) - { - if (buffer.length_ > 0) - { - // - // There is enough space in buffer but we need - // to move existing data at the beginning. - // - - #ifdef TEST - *logofs << "Transport: Moving " << buffer.length_ - << " bytes of data for " << "FD#" << fd_ - << " to make room in the buffer.\n" - << logofs_flush; - #endif - - memmove(buffer.data_.begin(), buffer.data_.begin() + - buffer.start_, buffer.length_); - } - - buffer.start_ = 0; - - #ifdef DEBUG - *logofs << "Transport: Made room for " - << buffer.data_.size() - buffer.start_ - << " bytes in buffer for " << "FD#" - << fd_ << ".\n" << logofs_flush; - #endif - } - else if ((buffer.length_ + size) > (int) buffer.data_.size()) - { - // - // Not enough space, so increase - // the size of the buffer. - // - - if (buffer.start_ != 0 && buffer.length_ > 0) - { - #ifdef TEST - *logofs << "Transport: Moving " << buffer.length_ - << " bytes of data for " << "FD#" << fd_ - << " to resize the buffer.\n" - << logofs_flush; - #endif - - memmove(buffer.data_.begin(), buffer.data_.begin() + - buffer.start_, buffer.length_); - } - - buffer.start_ = 0; - - unsigned int newSize = thresholdSize_; - - while (newSize < (unsigned int) buffer.length_ + size) - { - newSize <<= 1; - - if (newSize >= maximumSize_) - { - newSize = buffer.length_ + size + initialSize_; - } - } - - #ifdef DEBUG - *logofs << "Transport: Buffer for " << "FD#" << fd_ - << " will be enlarged from " << buffer.data_.size() - << " to at least " << buffer.length_ + size - << " bytes.\n" << logofs_flush; - #endif - - buffer.data_.resize(newSize); - - #ifdef TEST - if (newSize >= maximumSize_) - { - *logofs << "Transport: WARNING! Buffer for FD#" << fd_ - << " grown to reach size of " << newSize - << " bytes.\n" << logofs_flush; - } - #endif - - #ifdef TEST - *logofs << "Transport: Data buffer for " << "FD#" - << fd_ << " has now size " << buffer.data_.size() - << " and capacity " << buffer.data_.capacity() - << ".\n" << logofs_flush; - #endif - } - - return (buffer.length_ + size); -} - -void Transport::fullReset(T_buffer &buffer) -{ - // - // Force deallocation and allocation - // of the initial size. - // - - #ifdef TEST - *logofs << "Transport: Resetting buffer for " << "FD#" - << fd_ << " with size " << buffer.data_.size() - << " and capacity " << buffer.data_.capacity() - << ".\n" << logofs_flush; - #endif - - buffer.start_ = 0; - buffer.length_ = 0; - - if (buffer.data_.size() > (unsigned int) initialSize_ && - buffer.data_.capacity() > (unsigned int) initialSize_) - { - buffer.data_.clear(); - - buffer.data_.resize(initialSize_); - - #ifdef TEST - *logofs << "Transport: Data buffer for " << "FD#" - << fd_ << " shrunk to size " << buffer.data_.size() - << " and capacity " << buffer.data_.capacity() - << ".\n" << logofs_flush; - #endif - } -} - -ProxyTransport::ProxyTransport(int fd) : Transport(fd) -{ - #ifdef TEST - *logofs << "ProxyTransport: Going to create proxy transport " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - type_ = transport_proxy; - - // - // Set up the read buffer. - // - - r_buffer_.length_ = 0; - r_buffer_.start_ = 0; - - r_buffer_.data_.resize(initialSize_); - - // - // For now we own the buffer. - // - - owner_ = 1; - - // - // Set up ZLIB compression. - // - - int result; - - r_stream_.zalloc = NULL; - r_stream_.zfree = NULL; - r_stream_.opaque = NULL; - - r_stream_.next_in = NULL; - r_stream_.avail_in = 0; - - if ((result = inflateInit2(&r_stream_, 15)) != Z_OK) - { - #ifdef PANIC - *logofs << "ProxyTransport: PANIC! Failed initialization of ZLIB read stream. " - << "Error is '" << zError(result) << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed initialization of ZLIB read stream. " - << "Error is '" << zError(result) << "'.\n"; - - HandleCleanup(); - } - - if (control -> LocalStreamCompression) - { - w_stream_.zalloc = NULL; - w_stream_.zfree = NULL; - w_stream_.opaque = NULL; - - if ((result = deflateInit2(&w_stream_, control -> LocalStreamCompressionLevel, Z_DEFLATED, - 15, 9, Z_DEFAULT_STRATEGY)) != Z_OK) - { - #ifdef PANIC - *logofs << "ProxyTransport: PANIC! Failed initialization of ZLIB write stream. " - << "Error is '" << zError(result) << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Failed initialization of ZLIB write stream. " - << "Error is '" << zError(result) << "'.\n"; - - HandleCleanup(); - } - } - - // - // No ZLIB stream to flush yet. - // - - flush_ = 0; - - #ifdef REFERENCES - *logofs << "ProxyTransport: Created new object at " - << this << " out of " << ++references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -ProxyTransport::~ProxyTransport() -{ - #ifdef TEST - *logofs << "ProxyTransport: Going to destroy derived class " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - // - // Deallocate the ZLIB stream state. - // - - inflateEnd(&r_stream_); - - if (control -> LocalStreamCompression) - { - deflateEnd(&w_stream_); - } - - #ifdef REFERENCES - *logofs << "ProxyTransport: Deleted object at " - << this << " out of " << --references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -// -// Read data from its file descriptor. -// - -int ProxyTransport::read(unsigned char *data, unsigned int size) -{ - // - // If the remote peer is not compressing - // the stream then just return any byte - // read from the socket. - // - - if (control -> RemoteStreamCompression == 0) - { - int result = Transport::read(data, size); - - if (result <= 0) - { - return result; - } - - statistics -> addBytesIn(result); - - return result; - } - - // - // Return any pending data first. - // - - if (r_buffer_.length_ > 0) - { - // - // If the size of the buffer doesn't - // match the amount of data pending, - // force the caller to retry. - // - - if ((int) size < r_buffer_.length_) - { - #ifdef TEST - *logofs << "ProxyTransport: WARNING! Forcing a retry with " - << r_buffer_.length_ << " bytes pending and " - << size << " in the buffer.\n" - << logofs_flush; - #endif - - ESET(EAGAIN); - - return -1; - } - - int copied = (r_buffer_.length_ > ((int) size) ? - ((int) size) : r_buffer_.length_); - - memcpy(data, r_buffer_.data_.begin() + r_buffer_.start_, copied); - - // - // Update the buffer status. - // - - #ifdef DEBUG - *logofs << "ProxyTransport: Going to immediately return " << copied - << " bytes from proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - r_buffer_.length_ -= copied; - - if (r_buffer_.length_ == 0) - { - r_buffer_.start_ = 0; - } - else - { - r_buffer_.start_ += copied; - - #ifdef TEST - *logofs << "ProxyTransport: There are still " << r_buffer_.length_ - << " bytes in read buffer for proxy " << "FD#" - << fd_ << ".\n" << logofs_flush; - #endif - } - - return copied; - } - - // - // Read data in the user buffer. - // - - int result = Transport::read(data, size); - - if (result <= 0) - { - return result; - } - - statistics -> addBytesIn(result); - - // - // Decompress the data into the read - // buffer. - // - - #ifdef DEBUG - *logofs << "ProxyTransport: Going to decompress data for " - << "proxy FD#" << fd_ << ".\n" << logofs_flush; - #endif - - int saveTotalIn = r_stream_.total_in; - int saveTotalOut = r_stream_.total_out; - - int oldTotalIn = saveTotalIn; - int oldTotalOut = saveTotalOut; - - int diffTotalIn; - int diffTotalOut; - - #ifdef INSPECT - *logofs << "ProxyTransport: oldTotalIn = " << oldTotalIn - << ".\n" << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: oldTotalOut = " << oldTotalOut - << ".\n" << logofs_flush; - #endif - - r_stream_.next_in = (Bytef *) data; - r_stream_.avail_in = result; - - // - // Let ZLIB use all the space already - // available in the buffer. - // - - unsigned int newAvailOut = r_buffer_.data_.size() - r_buffer_.start_ - - r_buffer_.length_; - - #ifdef TEST - *logofs << "ProxyTransport: Initial decompress buffer is " - << newAvailOut << " bytes.\n" << logofs_flush; - #endif - - for (;;) - { - #ifdef INSPECT - *logofs << "\nProxyTransport: Running the decompress loop.\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_buffer_.length_ = " << r_buffer_.length_ - << ".\n" << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_buffer_.data_.size() = " << r_buffer_.data_.size() - << ".\n" << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: newAvailOut = " << newAvailOut - << ".\n" << logofs_flush; - #endif - - if (resize(r_buffer_, newAvailOut) < 0) - { - return -1; - } - - #ifdef INSPECT - *logofs << "ProxyTransport: r_buffer_.data_.size() = " - << r_buffer_.data_.size() << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_stream_.next_in = " - << (void *) r_stream_.next_in << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_stream_.avail_in = " - << r_stream_.avail_in << ".\n" - << logofs_flush; - #endif - - r_stream_.next_out = r_buffer_.data_.begin() + r_buffer_.start_ + - r_buffer_.length_; - - r_stream_.avail_out = newAvailOut; - - #ifdef INSPECT - *logofs << "ProxyTransport: r_stream_.next_out = " - << (void *) r_stream_.next_out << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_stream_.avail_out = " - << r_stream_.avail_out << ".\n" - << logofs_flush; - #endif - - int result = inflate(&r_stream_, Z_SYNC_FLUSH); - - #ifdef INSPECT - *logofs << "ProxyTransport: Called inflate() result is " - << result << ".\n" << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_stream_.avail_in = " - << r_stream_.avail_in << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_stream_.avail_out = " - << r_stream_.avail_out << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_stream_.total_in = " - << r_stream_.total_in << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_stream_.total_out = " - << r_stream_.total_out << ".\n" - << logofs_flush; - #endif - - diffTotalIn = r_stream_.total_in - oldTotalIn; - diffTotalOut = r_stream_.total_out - oldTotalOut; - - #ifdef INSPECT - *logofs << "ProxyTransport: diffTotalIn = " - << diffTotalIn << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: diffTotalOut = " - << diffTotalOut << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: r_buffer_.length_ = " - << r_buffer_.length_ << ".\n" - << logofs_flush; - #endif - - r_buffer_.length_ += diffTotalOut; - - #ifdef INSPECT - *logofs << "ProxyTransport: r_buffer_.length_ = " - << r_buffer_.length_ << ".\n" - << logofs_flush; - #endif - - oldTotalIn = r_stream_.total_in; - oldTotalOut = r_stream_.total_out; - - if (result == Z_OK) - { - if (r_stream_.avail_in == 0 && r_stream_.avail_out > 0) - { - break; - } - } - else if (result == Z_BUF_ERROR && r_stream_.avail_out > 0 && - r_stream_.avail_in == 0) - { - #ifdef TEST - *logofs << "ProxyTransport: WARNING! Raised Z_BUF_ERROR decompressing data.\n" - << logofs_flush; - #endif - - break; - } - else - { - #ifdef PANIC - *logofs << "ProxyTransport: PANIC! Decompression of data failed. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Decompression of data failed. Error is '" - << zError(result) << "'.\n"; - - finish(); - - return -1; - } - - // - // Add more bytes to the buffer. - // - - if (newAvailOut < thresholdSize_) - { - newAvailOut = thresholdSize_; - } - - #ifdef TEST - *logofs << "ProxyTransport: Need to add " << newAvailOut - << " bytes to the decompress buffer in read.\n" - << logofs_flush; - #endif - } - - diffTotalIn = r_stream_.total_in - saveTotalIn; - diffTotalOut = r_stream_.total_out - saveTotalOut; - - #ifdef DEBUG - *logofs << "ProxyTransport: Decompressed data from " - << diffTotalIn << " to " << diffTotalOut - << " bytes.\n" << logofs_flush; - #endif - - statistics -> addDecompressedBytes(diffTotalIn, diffTotalOut); - - // - // Check if the size of the buffer - // matches the produced data. - // - - if ((int) size < r_buffer_.length_) - { - #ifdef TEST - *logofs << "ProxyTransport: WARNING! Forcing a retry with " - << r_buffer_.length_ << " bytes pending and " - << size << " in the buffer.\n" - << logofs_flush; - #endif - - ESET(EAGAIN); - - return -1; - } - - // - // Copy the decompressed data to the - // provided buffer. - // - - int copied = (r_buffer_.length_ > ((int) size) ? - ((int) size) : r_buffer_.length_); - - #ifdef DEBUG - *logofs << "ProxyTransport: Going to return " << copied - << " bytes from proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - memcpy(data, r_buffer_.data_.begin() + r_buffer_.start_, copied); - - // - // Update the buffer status. - // - - r_buffer_.length_ -= copied; - - if (r_buffer_.length_ == 0) - { - r_buffer_.start_ = 0; - } - else - { - r_buffer_.start_ += copied; - - #ifdef TEST - *logofs << "ProxyTransport: There are still " << r_buffer_.length_ - << " bytes in read buffer for proxy FD#" << fd_ - << ".\n" << logofs_flush; - #endif - } - - return copied; -} - -// -// If required compress data, else write it to socket. -// - -int ProxyTransport::write(T_write type, const unsigned char *data, const unsigned int size) -{ - #ifdef TEST - if (size == 0) - { - *logofs << "ProxyTransport: WARNING! Write called for FD#" - << fd_ << " without any data to write.\n" - << logofs_flush; - - return 0; - } - #endif - - // - // If there is no compression revert to - // plain socket management. - // - - if (control -> LocalStreamCompression == 0) - { - int result = Transport::write(type, data, size); - - if (result <= 0) - { - return result; - } - - statistics -> addBytesOut(result); - - statistics -> updateBitrate(result); - - FlushCallback(result); - - return result; - } - - #ifdef DEBUG - *logofs << "ProxyTransport: Going to compress " << size - << " bytes to write buffer for proxy FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - // - // Compress data into the write buffer. - // - - int saveTotalIn = w_stream_.total_in; - int saveTotalOut = w_stream_.total_out; - - int oldTotalIn = saveTotalIn; - int oldTotalOut = saveTotalOut; - - int diffTotalIn; - int diffTotalOut; - - #ifdef INSPECT - *logofs << "ProxyTransport: oldTotalIn = " << oldTotalIn - << ".\n" << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: oldTotalOut = " << oldTotalOut - << ".\n" << logofs_flush; - #endif - - w_stream_.next_in = (Bytef *) data; - w_stream_.avail_in = size; - - // - // Let ZLIB use all the space already - // available in the buffer. - // - - unsigned int newAvailOut = w_buffer_.data_.size() - w_buffer_.start_ - - w_buffer_.length_; - - #ifdef TEST - *logofs << "ProxyTransport: Initial compress buffer is " - << newAvailOut << " bytes.\n" << logofs_flush; - #endif - - for (;;) - { - #ifdef INSPECT - *logofs << "\nProxyTransport: Running the compress loop.\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.length_ = " - << w_buffer_.length_ << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.data_.size() = " - << w_buffer_.data_.size() << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: newAvailOut = " - << newAvailOut << ".\n" - << logofs_flush; - #endif - - if (resize(w_buffer_, newAvailOut) < 0) - { - return -1; - } - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.data_.size() = " - << w_buffer_.data_.size() << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.next_in = " - << (void *) w_stream_.next_in << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.avail_in = " - << w_stream_.avail_in << ".\n" - << logofs_flush; - #endif - - w_stream_.next_out = w_buffer_.data_.begin() + w_buffer_.start_ + - w_buffer_.length_; - - w_stream_.avail_out = newAvailOut; - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.next_out = " - << (void *) w_stream_.next_out << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.avail_out = " - << w_stream_.avail_out << ".\n" - << logofs_flush; - #endif - - int result = deflate(&w_stream_, (type == write_delayed ? - Z_NO_FLUSH : Z_SYNC_FLUSH)); - - #ifdef INSPECT - *logofs << "ProxyTransport: Called deflate() result is " - << result << ".\n" << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.avail_in = " - << w_stream_.avail_in << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.avail_out = " - << w_stream_.avail_out << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.total_in = " - << w_stream_.total_in << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.total_out = " - << w_stream_.total_out << ".\n" - << logofs_flush; - #endif - - diffTotalOut = w_stream_.total_out - oldTotalOut; - diffTotalIn = w_stream_.total_in - oldTotalIn; - - #ifdef INSPECT - *logofs << "ProxyTransport: diffTotalIn = " - << diffTotalIn << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: diffTotalOut = " - << diffTotalOut << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.length_ = " - << w_buffer_.length_ << ".\n" - << logofs_flush; - #endif - - w_buffer_.length_ += diffTotalOut; - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.length_ = " - << w_buffer_.length_ << ".\n" - << logofs_flush; - #endif - - oldTotalOut = w_stream_.total_out; - oldTotalIn = w_stream_.total_in; - - if (result == Z_OK) - { - if (w_stream_.avail_in == 0 && w_stream_.avail_out > 0) - { - break; - } - } - else if (result == Z_BUF_ERROR && w_stream_.avail_out > 0 && - w_stream_.avail_in == 0) - { - #ifdef TEST - *logofs << "ProxyTransport: WARNING! Raised Z_BUF_ERROR compressing data.\n" - << logofs_flush; - #endif - - break; - } - else - { - #ifdef PANIC - *logofs << "ProxyTransport: PANIC! Compression of data failed. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Compression of data failed. Error is '" - << zError(result) << "'.\n"; - - finish(); - - return -1; - } - - // - // Add more bytes to the buffer. - // - - if (newAvailOut < thresholdSize_) - { - newAvailOut = thresholdSize_; - } - - #ifdef TEST - *logofs << "ProxyTransport: Need to add " << newAvailOut - << " bytes to the compress buffer in write.\n" - << logofs_flush; - #endif - } - - diffTotalIn = w_stream_.total_in - saveTotalIn; - diffTotalOut = w_stream_.total_out - saveTotalOut; - - #ifdef TEST - - *logofs << "ProxyTransport: Compressed data from " - << diffTotalIn << " to " << diffTotalOut - << " bytes.\n" << logofs_flush; - - if (diffTotalIn != (int) size) - { - #ifdef PANIC - *logofs << "ProxyTransport: PANIC! Bytes provided to ZLIB stream " - << "should be " << size << " but they look to be " - << diffTotalIn << ".\n" << logofs_flush; - #endif - } - - #endif - - // - // Find out what we have to do with the - // produced data. - // - - if (type == write_immediate) - { - // - // If user requested an immediate write we - // flushed the ZLIB buffer. We can now reset - // the counter and write data to socket. - // - - flush_ = 0; - - #ifdef TEST - *logofs << "ProxyTransport: Write buffer for proxy FD#" << fd_ - << " has data for " << w_buffer_.length_ << " bytes.\n" - << logofs_flush; - - *logofs << "ProxyTransport: Start is " << w_buffer_.start_ - << " length is " << w_buffer_.length_ << " flush is " - << flush_ << " size is " << w_buffer_.data_.size() - << " capacity is " << w_buffer_.data_.capacity() - << ".\n" << logofs_flush; - #endif - - // - // Alternatively may try to write only if - // the socket is not blocked. - // - // if (w_buffer_.length_ > 0 && blocked_ == 0) - // { - // ... - // } - // - - if (w_buffer_.length_ > 0) - - { - #ifdef TEST - *logofs << "ProxyTransport: Writing " << w_buffer_.length_ - << " bytes of produced data to FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - int result = Transport::flush(); - - if (result < 0) - { - return -1; - } - } - } - else - { - // - // We haven't flushed the ZLIB compression - // buffer, so user will have to call proxy - // transport's flush explicitly. - // - - flush_ += diffTotalIn; - } - - // - // We either wrote the data or added it to the - // write buffer. It's convenient to update the - // counters at this stage to get the current - // bitrate earlier. - // - - statistics -> addCompressedBytes(diffTotalIn, diffTotalOut); - - statistics -> addBytesOut(diffTotalOut); - - statistics -> updateBitrate(diffTotalOut); - - FlushCallback(diffTotalOut); - - #ifdef TEST - *logofs << "ProxyTransport: Write buffer for proxy FD#" << fd_ - << " has data for " << w_buffer_.length_ << " bytes.\n" - << logofs_flush; - - *logofs << "ProxyTransport: Start is " << w_buffer_.start_ - << " length is " << w_buffer_.length_ << " flush is " - << flush_ << " size is " << w_buffer_.data_.size() - << " capacity is " << w_buffer_.data_.capacity() - << ".\n" << logofs_flush; - #endif - - return size; -} - -// -// Write data to its file descriptor. -// - -int ProxyTransport::flush() -{ - // - // If there is no compression or we already compressed - // outgoing data and just need to write it to socket - // because of previous incomplete writes then revert - // to plain socket management. - // - - if (flush_ == 0 || control -> LocalStreamCompression == 0) - { - int result = Transport::flush(); - - if (result < 0) - { - return -1; - } - - return result; - } - - #ifdef DEBUG - *logofs << "ProxyTransport: Going to flush compression on " - << "proxy FD#" << fd_ << ".\n" << logofs_flush; - #endif - - #ifdef TEST - *logofs << "ProxyTransport: Flush counter for proxy FD#" << fd_ - << " is " << flush_ << " bytes.\n" << logofs_flush; - #endif - - // - // Flush ZLIB stream into the write buffer. - // - - int saveTotalIn = w_stream_.total_in; - int saveTotalOut = w_stream_.total_out; - - int oldTotalIn = saveTotalIn; - int oldTotalOut = saveTotalOut; - - int diffTotalOut; - int diffTotalIn; - - #ifdef INSPECT - *logofs << "ProxyTransport: oldTotalIn = " << oldTotalIn - << ".\n" << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: oldTotalOut = " << oldTotalOut - << ".\n" << logofs_flush; - #endif - - w_stream_.next_in = w_buffer_.data_.begin() + w_buffer_.start_ + w_buffer_.length_; - w_stream_.avail_in = 0; - - // - // Let ZLIB use all the space already - // available in the buffer. - // - - unsigned int newAvailOut = w_buffer_.data_.size() - w_buffer_.start_ - - w_buffer_.length_; - - #ifdef DEBUG - *logofs << "ProxyTransport: Initial flush buffer is " - << newAvailOut << " bytes.\n" << logofs_flush; - #endif - - for (;;) - { - #ifdef INSPECT - *logofs << "\nProxyTransport: Running the flush loop.\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.length_ = " - << w_buffer_.length_ << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.data_.size() = " - << w_buffer_.data_.size() << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: newAvailOut = " - << newAvailOut << ".\n" - << logofs_flush; - #endif - - if (resize(w_buffer_, newAvailOut) < 0) - { - return -1; - } - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.data_.size() = " - << w_buffer_.data_.size() << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.next_in = " - << (void *) w_stream_.next_in << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.avail_in = " - << w_stream_.avail_in << ".\n" - << logofs_flush; - #endif - - w_stream_.next_out = w_buffer_.data_.begin() + w_buffer_.start_ + - w_buffer_.length_; - - w_stream_.avail_out = newAvailOut; - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.next_out = " - << (void *) w_stream_.next_out << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.avail_out = " - << w_stream_.avail_out << ".\n" - << logofs_flush; - #endif - - int result = deflate(&w_stream_, Z_SYNC_FLUSH); - - #ifdef INSPECT - *logofs << "ProxyTransport: Called deflate() result is " - << result << ".\n" << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.avail_in = " - << w_stream_.avail_in << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.avail_out = " - << w_stream_.avail_out << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.total_in = " - << w_stream_.total_in << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_stream_.total_out = " - << w_stream_.total_out << ".\n" - << logofs_flush; - #endif - - diffTotalOut = w_stream_.total_out - oldTotalOut; - diffTotalIn = w_stream_.total_in - oldTotalIn; - - #ifdef INSPECT - *logofs << "ProxyTransport: diffTotalIn = " - << diffTotalIn << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: diffTotalOut = " - << diffTotalOut << ".\n" - << logofs_flush; - #endif - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.length_ = " - << w_buffer_.length_ << ".\n" - << logofs_flush; - #endif - - w_buffer_.length_ += diffTotalOut; - - #ifdef INSPECT - *logofs << "ProxyTransport: w_buffer_.length_ = " - << w_buffer_.length_ << ".\n" - << logofs_flush; - #endif - - oldTotalOut = w_stream_.total_out; - oldTotalIn = w_stream_.total_in; - - if (result == Z_OK) - { - if (w_stream_.avail_in == 0 && w_stream_.avail_out > 0) - { - break; - } - } - else if (result == Z_BUF_ERROR && w_stream_.avail_out > 0 && - w_stream_.avail_in == 0) - { - #ifdef TEST - *logofs << "ProxyTransport: WARNING! Raised Z_BUF_ERROR flushing data.\n" - << logofs_flush; - #endif - - break; - } - else - { - #ifdef PANIC - *logofs << "ProxyTransport: PANIC! Flush of compressed data failed. " - << "Error is '" << zError(result) << "'.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Flush of compressed data failed. Error is '" - << zError(result) << "'.\n"; - - finish(); - - return -1; - } - - // - // Add more bytes to the buffer. - // - - if (newAvailOut < thresholdSize_) - { - newAvailOut = thresholdSize_; - } - - #ifdef TEST - *logofs << "ProxyTransport: Need to add " << newAvailOut - << " bytes to the compress buffer in flush.\n" - << logofs_flush; - #endif - } - - diffTotalIn = w_stream_.total_in - saveTotalIn; - diffTotalOut = w_stream_.total_out - saveTotalOut; - - #ifdef TEST - *logofs << "ProxyTransport: Compressed flush data from " - << diffTotalIn << " to " << diffTotalOut - << " bytes.\n" << logofs_flush; - #endif - - // - // Time to move data from the write - // buffer to the real link. - // - - #ifdef DEBUG - *logofs << "ProxyTransport: Reset flush counter for proxy FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - flush_ = 0; - - #ifdef TEST - *logofs << "ProxyTransport: Write buffer for proxy FD#" << fd_ - << " has data for " << w_buffer_.length_ << " bytes.\n" - << logofs_flush; - - *logofs << "ProxyTransport: Start is " << w_buffer_.start_ - << " length is " << w_buffer_.length_ << " flush is " - << flush_ << " size is " << w_buffer_.data_.size() - << " capacity is " << w_buffer_.data_.capacity() - << ".\n" << logofs_flush; - #endif - - int result = Transport::flush(); - - if (result < 0) - { - return -1; - } - - // - // Update all the counters. - // - - statistics -> addCompressedBytes(diffTotalIn, diffTotalOut); - - statistics -> addBytesOut(diffTotalOut); - - statistics -> updateBitrate(diffTotalOut); - - FlushCallback(diffTotalOut); - - return result; -} - -unsigned int ProxyTransport::getPending(unsigned char *&data) -{ - // - // Return a pointer to the data in the - // read buffer. It is up to the caller - // to ensure that the data is consumed - // before the read buffer is reused. - // - - if (r_buffer_.length_ > 0) - { - unsigned int size = r_buffer_.length_; - - data = r_buffer_.data_.begin() + r_buffer_.start_; - - #ifdef DEBUG - *logofs << "ProxyTransport: Returning " << size - << " pending bytes from proxy FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - r_buffer_.length_ = 0; - r_buffer_.start_ = 0; - - // - // Prevent the deletion of the buffer. - // - - owner_ = 0; - - return size; - } - - #ifdef TEST - *logofs << "ProxyTransport: WARNING! No pending data " - << "for proxy FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - data = NULL; - - return 0; -} - -void ProxyTransport::fullReset() -{ - blocked_ = 0; - finish_ = 0; - flush_ = 0; - - if (control -> RemoteStreamCompression) - { - inflateReset(&r_stream_); - } - - if (control -> LocalStreamCompression) - { - deflateReset(&w_stream_); - } - - if (owner_ == 1) - { - Transport::fullReset(r_buffer_); - } - - Transport::fullReset(w_buffer_); -} - -AgentTransport::AgentTransport(int fd) : Transport(fd) -{ - #ifdef TEST - *logofs << "AgentTransport: Going to create agent transport " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - type_ = transport_agent; - - // - // Set up the read buffer. - // - - r_buffer_.length_ = 0; - r_buffer_.start_ = 0; - - r_buffer_.data_.resize(initialSize_); - - // - // For now we own the buffer. - // - - owner_ = 1; - - // - // Set up the mutexes. - // - - #ifdef THREADS - - pthread_mutexattr_t m_attributes; - - pthread_mutexattr_init(&m_attributes); - - // - // Interfaces in pthread to handle mutex - // type do not work in current version. - // - - m_attributes.__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP; - - if (pthread_mutex_init(&m_read_, &m_attributes) != 0) - { - #ifdef TEST - *logofs << "AgentTransport: Child: Creation of read mutex failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - } - - if (pthread_mutex_init(&m_write_, &m_attributes) != 0) - { - #ifdef TEST - *logofs << "AgentTransport: Child: Creation of write mutex failed. " - << "Error is " << EGET() << " '" << ESTR() - << "'.\n" << logofs_flush; - #endif - } - - #endif - - #ifdef REFERENCES - *logofs << "AgentTransport: Child: Created new object at " - << this << " out of " << ++references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -AgentTransport::~AgentTransport() -{ - #ifdef TEST - *logofs << "AgentTransport: Going to destroy derived class " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - // - // Unlock and free all mutexes. - // - - #ifdef THREADS - - pthread_mutex_unlock(&m_read_); - pthread_mutex_unlock(&m_write_); - - pthread_mutex_destroy(&m_read_); - pthread_mutex_destroy(&m_write_); - - #endif - - #ifdef REFERENCES - *logofs << "AgentTransport: Child: Deleted object at " - << this << " out of " << --references_ - << " allocated references.\n" << logofs_flush; - #endif -} - -// -// Read data enqueued by the other thread. -// - -int AgentTransport::read(unsigned char *data, unsigned int size) -{ - #ifdef THREADS - - lockRead(); - - #endif - - #ifdef DEBUG - *logofs << "AgentTransport: Child: Going to read " << size - << " bytes from " << "FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - int copied = -1; - - if (r_buffer_.length_ > 0) - { - if ((int) size < r_buffer_.length_) - { - #ifdef TEST - *logofs << "AgentTransport: WARNING! Forcing a retry with " - << r_buffer_.length_ << " bytes pending and " - << size << " in the buffer.\n" - << logofs_flush; - #endif - - ESET(EAGAIN); - } - else - { - copied = (r_buffer_.length_ > ((int) size) ? - ((int) size) : r_buffer_.length_); - - memcpy(data, r_buffer_.data_.begin() + r_buffer_.start_, copied); - - // - // Update the buffer status. - // - - #ifdef TEST - *logofs << "AgentTransport: Child: Going to immediately return " - << copied << " bytes from FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - #ifdef DUMP - - *logofs << "AgentTransport: Child: Dumping content of read data.\n" - << logofs_flush; - - DumpData(data, copied); - - #endif - - r_buffer_.length_ -= copied; - - if (r_buffer_.length_ == 0) - { - r_buffer_.start_ = 0; - } - else - { - r_buffer_.start_ += copied; - - #ifdef TEST - *logofs << "AgentTransport: Child: There are still " - << r_buffer_.length_ << " bytes in read buffer for " - << "FD#" << fd_ << ".\n" << logofs_flush; - #endif - } - } - } - else - { - #ifdef DEBUG - *logofs << "AgentTransport: Child: No data can be got " - << "from read buffer for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - ESET(EAGAIN); - } - - #ifdef THREADS - - unlockRead(); - - #endif - - return copied; -} - -// -// Write data to buffer so that the other -// thread can get it. -// - -int AgentTransport::write(T_write type, const unsigned char *data, const unsigned int size) -{ - #ifdef THREADS - - lockWrite(); - - #endif - - // - // Just append data to socket's write buffer. - // Note that we don't care if buffer exceeds - // the size limits set for this type of - // transport. - // - - #ifdef TEST - *logofs << "AgentTransport: Child: Going to append " << size - << " bytes to write buffer for " << "FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - int copied = -1; - - if (resize(w_buffer_, size) < 0) - { - finish(); - - ESET(EPIPE); - } - else - { - memmove(w_buffer_.data_.begin() + w_buffer_.start_ + w_buffer_.length_, data, size); - - w_buffer_.length_ += size; - - #ifdef DUMP - - *logofs << "AgentTransport: Child: Dumping content of written data.\n" - << logofs_flush; - - DumpData(data, size); - - #endif - - #ifdef TEST - *logofs << "AgentTransport: Child: Write buffer for FD#" << fd_ - << " has data for " << w_buffer_.length_ << " bytes.\n" - << logofs_flush; - - *logofs << "AgentTransport: Child: Start is " << w_buffer_.start_ - << " length is " << w_buffer_.length_ << " size is " - << w_buffer_.data_.size() << " capacity is " - << w_buffer_.data_.capacity() << ".\n" - << logofs_flush; - #endif - - copied = size; - } - - // - // Let child access again the read buffer. - // - - #ifdef THREADS - - unlockWrite(); - - #endif - - return copied; -} - -int AgentTransport::flush() -{ - // - // In case of memory-to-memory transport - // this function should never be called. - // - - #ifdef PANIC - *logofs << "AgentTransport: Child: PANIC! Called flush() for " - << "memory to memory transport on " << "FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Called flush() for " - << "memory to memory transport on " << "FD#" - << fd_ << ".\n"; - - HandleAbort(); -} - -int AgentTransport::drain(int limit, int timeout) -{ - // - // We can't drain the channel in the case - // of the memory-to-memory transport. Data - // is enqueued for the agent to read but - // the agent could require multiple loops - // to read it all. - // - - // - // In case of memory-to-memory transport - // this function should never be called. - // - - #ifdef PANIC - *logofs << "AgentTransport: Child: PANIC! Called drain() for " - << "memory to memory transport on " << "FD#" - << fd_ << ".\n" << logofs_flush; - #endif - - cerr << "Error" << ": Called drain() for " - << "memory to memory transport on " << "FD#" - << fd_ << ".\n"; - - HandleAbort(); -} - -unsigned int AgentTransport::getPending(unsigned char *&data) -{ - #ifdef THREADS - - lockRead(); - - #endif - - if (r_buffer_.length_ > 0) - { - unsigned int size = r_buffer_.length_; - - data = r_buffer_.data_.begin() + r_buffer_.start_; - - #ifdef DEBUG - *logofs << "AgentTransport: Child: Returning " << size - << " pending bytes from FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - r_buffer_.length_ = 0; - r_buffer_.start_ = 0; - - #ifdef THREADS - - unlockRead(); - - #endif - - // - // Prevent the deletion of the buffer. - // - - owner_ = 0; - - return size; - } - - #ifdef TEST - *logofs << "AgentTransport: WARNING! No pending data " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - #ifdef THREADS - - unlockRead(); - - #endif - - data = NULL; - - return 0; -} - -void AgentTransport::fullReset() -{ - #ifdef THREADS - - lockRead(); - lockWrite(); - - #endif - - #ifdef TEST - *logofs << "AgentTransport: Child: Resetting transport " - << "for FD#" << fd_ << ".\n" << logofs_flush; - #endif - - blocked_ = 0; - finish_ = 0; - - if (owner_ == 1) - { - Transport::fullReset(r_buffer_); - } - - Transport::fullReset(w_buffer_); -} - -int AgentTransport::enqueue(const char *data, const int size) -{ - #ifdef THREADS - - lockRead(); - - #endif - - if (finish_ == 1) - { - #if defined(PARENT) && defined(TEST) - *logofs << "AgentTransport: Parent: Returning EPIPE in " - << "write for finishing FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - ESET(EPIPE); - - return -1; - } - - // - // Always allow the agent to write - // all its data. - // - - int toPut = size; - - #if defined(PARENT) && defined(TEST) - *logofs << "AgentTransport: Parent: Going to put " << toPut - << " bytes into read buffer for FD#" << fd_ - << ". Buffer length is " << r_buffer_.length_ - << ".\n" << logofs_flush; - #endif - - if (resize(r_buffer_, toPut) < 0) - { - finish(); - - #ifdef THREADS - - unlockRead(); - - #endif - - return -1; - } - - memcpy(r_buffer_.data_.begin() + r_buffer_.start_ + r_buffer_.length_, data, toPut); - - r_buffer_.length_ += toPut; - - #if defined(DUMP) && defined(PARENT) - - *logofs << "AgentTransport: Parent: Dumping content of enqueued data.\n" - << logofs_flush; - - DumpData((const unsigned char *) data, toPut); - - #endif - - #if defined(PARENT) && defined(TEST) - *logofs << "AgentTransport: Parent: Read buffer for FD#" << fd_ - << " has now data for " << r_buffer_.length_ - << " bytes.\n" << logofs_flush; - - *logofs << "AgentTransport: Parent: Start is " << r_buffer_.start_ - << " length is " << r_buffer_.length_ << " size is " - << r_buffer_.data_.size() << " capacity is " - << r_buffer_.data_.capacity() << ".\n" - << logofs_flush; - #endif - - #ifdef THREADS - - unlockRead(); - - #endif - - return toPut; -} - -int AgentTransport::dequeue(char *data, int size) -{ - #ifdef THREADS - - lockWrite(); - - #endif - - if (w_buffer_.length_ == 0) - { - if (finish_ == 1) - { - #if defined(PARENT) && defined(TEST) - *logofs << "AgentTransport: Parent: Returning 0 in read " - << "for finishing FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - return 0; - } - - #if defined(PARENT) && defined(TEST) - *logofs << "AgentTransport: Parent: No data can be read " - << "from write buffer for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - ESET(EAGAIN); - - #ifdef THREADS - - unlockWrite(); - - #endif - - return -1; - } - - // - // Return as many bytes as possible. - // - - int toGet = ((int) size > w_buffer_.length_ ? w_buffer_.length_ : size); - - #if defined(PARENT) && defined(TEST) - *logofs << "AgentTransport: Parent: Going to get " << toGet - << " bytes from write buffer for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - memcpy(data, w_buffer_.data_.begin() + w_buffer_.start_, toGet); - - w_buffer_.start_ += toGet; - w_buffer_.length_ -= toGet; - - #if defined(DUMP) && defined(PARENT) - - *logofs << "AgentTransport: Parent: Dumping content of dequeued data.\n" - << logofs_flush; - - DumpData((const unsigned char *) data, toGet); - - #endif - - #if defined(PARENT) && defined(TEST) - *logofs << "AgentTransport: Parent: Write buffer for FD#" << fd_ - << " has now data for " << length() << " bytes.\n" - << logofs_flush; - - *logofs << "AgentTransport: Parent: Start is " << w_buffer_.start_ - << " length is " << w_buffer_.length_ << " size is " - << w_buffer_.data_.size() << " capacity is " - << w_buffer_.data_.capacity() << ".\n" - << logofs_flush; - #endif - - #ifdef THREADS - - unlockWrite(); - - #endif - - return toGet; -} - -int AgentTransport::dequeuable() -{ - if (finish_ == 1) - { - #if defined(PARENT) && defined(TEST) - *logofs << "AgentTransport: Parent: Returning EPIPE in " - << "readable for finishing FD#" << fd_ - << ".\n" << logofs_flush; - #endif - - ESET(EPIPE); - - return -1; - } - - #if defined(PARENT) && defined(TEST) - *logofs << "AgentTransport: Parent: Returning " - << w_buffer_.length_ << " as data readable " - << "from read buffer for FD#" << fd_ << ".\n" - << logofs_flush; - #endif - - return w_buffer_.length_; -} - -#ifdef THREADS - -int AgentTransport::lockRead() -{ - for (;;) - { - int result = pthread_mutex_lock(&m_read_); - - if (result == 0) - { - #ifdef DEBUG - *logofs << "AgentTransport: Read mutex locked by thread id " - << pthread_self() << ".\n" << logofs_flush; - #endif - - return 0; - } - else if (EGET() == EINTR) - { - continue; - } - else - { - #ifdef WARNING - *logofs << "AgentTransport: WARNING! Locking of read mutex by thread id " - << pthread_self() << " returned " << result << ". Error is '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - return result; - } - } -} - -int AgentTransport::lockWrite() -{ - for (;;) - { - int result = pthread_mutex_lock(&m_write_); - - if (result == 0) - { - #ifdef DEBUG - *logofs << "AgentTransport: Write mutex locked by thread id " - << pthread_self() << ".\n" << logofs_flush; - #endif - - return 0; - } - else if (EGET() == EINTR) - { - continue; - } - else - { - #ifdef WARNING - *logofs << "AgentTransport: WARNING! Locking of write mutex by thread id " - << pthread_self() << " returned " << result << ". Error is '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - return result; - } - } -} - -int AgentTransport::unlockRead() -{ - for (;;) - { - int result = pthread_mutex_unlock(&m_read_); - - if (result == 0) - { - #ifdef DEBUG - *logofs << "AgentTransport: Read mutex unlocked by thread id " - << pthread_self() << ".\n" << logofs_flush; - #endif - - return 0; - } - else if (EGET() == EINTR) - { - continue; - } - else - { - #ifdef WARNING - *logofs << "AgentTransport: WARNING! Unlocking of read mutex by thread id " - << pthread_self() << " returned " << result << ". Error is '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - return result; - } - } -} - -int AgentTransport::unlockWrite() -{ - for (;;) - { - int result = pthread_mutex_unlock(&m_write_); - - if (result == 0) - { - #ifdef DEBUG - *logofs << "AgentTransport: Write mutex unlocked by thread id " - << pthread_self() << ".\n" << logofs_flush; - #endif - - return 0; - } - else if (EGET() == EINTR) - { - continue; - } - else - { - #ifdef WARNING - *logofs << "AgentTransport: WARNING! Unlocking of write mutex by thread id " - << pthread_self() << " returned " << result << ". Error is '" - << ESTR() << "'.\n" << logofs_flush; - #endif - - return result; - } - } -} - -#endif diff --git a/nxcomp/Transport.h b/nxcomp/Transport.h deleted file mode 100644 index 047396af6..000000000 --- a/nxcomp/Transport.h +++ /dev/null @@ -1,577 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Transport_H -#define Transport_H - -#include -#include - -#include -#include -#include - -#include "Misc.h" -#include "Control.h" - -#include "Types.h" -#include "Timestamp.h" -#include "Socket.h" - -// -// Set the verbosity level. -// - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Define this to lock and unlock the -// memory-to-memory transport buffers -// before they are accessed. The code -// is outdated and doesn't work with -// the current pthread library. -// - -#undef THREADS - -// -// Define this to know when a socket -// is created or destroyed. -// - -#undef REFERENCES - -// -// Size of buffer if not set by user. -// - -#define TRANSPORT_BUFFER_DEFAULT_SIZE 16384 - -// -// Type of transport. -// - -typedef enum -{ - transport_base, - transport_proxy, - transport_agent, - transport_last_tag - -} T_transport_type; - -// -// This class handles the buffered I/O on -// the network sockets. -// - -// -// TODO: This class is useful but adds a lot of -// overhead. There are many improvements we can -// make here: -// -// - There should be a generic Buffer class, ac- -// comodating a list of memory buffers. This -// would enable the use of the readv() and -// writev() functions to perform the I/O on -// the socket. -// -// - The buffering should be moved to the Write- -// Buffer and ReadBuffer classes. By performing -// the buffering here and there, we are dupli- -// cating a lot of code and are adding a lot -// of useless memory copies. -// -// - Stream compression should be removed. The -// proxy should compress the frames based on -// the type and should include the length of -// the decompressed data in the header of the -// packet. Besides avoiding the compression -// of packets that cannot be reduced in size, -// we would also save the additional memory -// allocations due to the fact that we don't -// know the size of the decode buffer at the -// time we read the packet from the network. -// -// - The other utilities implemented here, like -// the functions forcing a write on the socket -// or waiting for more data to become available -// should be moved to the Proxy or the Channel -// classes. -// - -class Transport -{ - public: - - // - // Member functions. - // - - Transport(int fd); - - virtual ~Transport(); - - int fd() const - { - return fd_; - } - - T_transport_type getType() - { - return type_; - } - - // - // Virtual members redefined by proxy - // and 'memory-to-memory' I/O layers. - // - - virtual int read(unsigned char *data, unsigned int size); - - virtual int write(T_write type, const unsigned char *data, const unsigned int size); - - virtual int flush(); - - virtual int drain(int limit, int timeout); - - virtual void finish() - { - fullReset(); - - finish_ = 1; - } - - virtual int length() const - { - return w_buffer_.length_; - } - - virtual int pending() const - { - return 0; - } - - virtual int readable() const - { - return GetBytesReadable(fd_); - } - - virtual int writable() const - { - return GetBytesWritable(fd_); - } - - virtual int queued() const - { - return GetBytesQueued(fd_); - } - - virtual int flushable() const - { - return 0; - } - - virtual int wait(int timeout) const; - - void setSize(unsigned int initialSize, - unsigned int thresholdSize, - unsigned int maximumSize); - - // - // Return a pointer to the data - // in the read buffer. - // - - virtual unsigned int getPending(unsigned char *&data) - { - data = NULL; - - return 0; - } - - virtual void pendingReset() - { - } - - virtual void partialReset() - { - partialReset(w_buffer_); - } - - virtual void fullReset(); - - int blocked() const - { - return blocked_; - } - - protected: - - // - // Make room in the buffer to accommodate - // at least size bytes. - // - - int resize(T_buffer &buffer, const int &size); - - void partialReset(T_buffer &buffer) - { - if (buffer.length_ == 0 && - (buffer.data_.size() > initialSize_ || - buffer.data_.capacity() > initialSize_)) - { - fullReset(buffer); - } - } - - void fullReset(T_buffer &buffer); - - // - // Data members. - // - - int fd_; - - int blocked_; - int finish_; - - T_buffer w_buffer_; - - unsigned int initialSize_; - unsigned int thresholdSize_; - unsigned int maximumSize_; - - T_transport_type type_; - - private: - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -// -// This class handles buffered I/O and -// compression of the proxy stream. -// - -class ProxyTransport : public Transport -{ - public: - - ProxyTransport(int fd); - - virtual ~ProxyTransport(); - - virtual int read(unsigned char *data, unsigned int size); - - virtual int write(T_write type, const unsigned char *data, const unsigned int size); - - virtual int flush(); - - // - // Same as in the base class. - // - // virtual int drain(int limit, int timeout); - // - // virtual void finish(); - // - - // - // Same as in the base class. - // - // virtual int length() const - // - - virtual int pending() const - { - return r_buffer_.length_; - } - - // - // Same as in the base class. - // - // virtual int readable() const; - // - // virtual int writable() const; - // - // virtual int queued() const; - // - - virtual int flushable() const - { - return flush_; - } - - // - // Same as in the base class, but - // should not be called. - // - // int drained() const; - // - // Same as in the base class. - // - // virtual int wait(int timeout) const; - // - // Same as in the base class. - // - // void setSize(unsigned int initialSize, - // unsigned int thresholdSize, - // unsigned int maximumSize); - // - - virtual unsigned int getPending(unsigned char *&data); - - virtual void pendingReset() - { - owner_ = 1; - } - - virtual void partialReset() - { - if (owner_ == 1) - { - Transport::partialReset(r_buffer_); - } - - Transport::partialReset(w_buffer_); - } - - virtual void fullReset(); - - // - // Same as in the base class. - // - // int blocked() const; - // - - protected: - - int flush_; - int owner_; - - T_buffer r_buffer_; - - z_stream r_stream_; - z_stream w_stream_; - - private: - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -// -// Handle memory-to-memory data transfers between -// an agent and the proxy. -// - -class AgentTransport : public Transport -{ - public: - - AgentTransport(int fd); - - virtual ~AgentTransport(); - - virtual int read(unsigned char *data, unsigned int size); - - virtual int write(T_write type, const unsigned char *data, const unsigned int size); - - // - // These two should never be called. - // - - virtual int flush(); - - virtual int drain(int limit, int timeout); - - // - // Same as in the base class. - // - // virtual void finish(); - // - - // - // Same as in the base class. - // - // virtual int length() const - // - - virtual int pending() const - { - return r_buffer_.length_; - } - - // - // These are intended to operate only - // on the internal buffers. - // - - virtual int readable() const - { - return r_buffer_.length_; - } - - virtual int writable() const - { - return control -> TransportMaximumBufferSize; - } - - virtual int queued() const - { - return 0; - } - - // - // Same as in the base class. - // - // virtual int flushable() const; - // - // Same as in the base class, but - // should not be called. - // - // int drained() const; - // - - // - // Return immediately or will - // block until the timeout. - // - - virtual int wait(int timeout) const - { - return 0; - } - - // - // Same as in the base class. - // - // void setSize(unsigned int initialSize, - // unsigned int thresholdSize, - // unsigned int maximumSize); - // - - virtual unsigned int getPending(unsigned char *&data); - - virtual void pendingReset() - { - owner_ = 1; - } - - virtual void partialReset() - { - if (owner_ == 1) - { - Transport::partialReset(r_buffer_); - } - - Transport::partialReset(w_buffer_); - } - - virtual void fullReset(); - - // - // Same as in the base class. - // - // int blocked() const; - // - - // - // The following are specific of the - // memory-to-memory transport. - // - - int enqueue(const char *data, const int size); - - int dequeue(char *data, int size); - - int queuable() - { - // - // Always allow the agent to enqueue - // more data. - // - - return control -> TransportMaximumBufferSize; - } - - int dequeuable(); - - protected: - - // - // Lock the buffer to handle reads and - // writes safely. - // - - #ifdef THREADS - - int lockRead(); - int lockWrite(); - - int unlockRead(); - int unlockWrite(); - - #endif - - // - // Data members. - // - - int owner_; - - T_buffer r_buffer_; - - // - // Mutexes for safe read and write. - // - - #ifdef THREADS - - pthread_mutex_t m_read_; - pthread_mutex_t m_write_; - - #endif - - private: - - #ifdef REFERENCES - - static int references_; - - #endif -}; - -#endif /* Transport_H */ diff --git a/nxcomp/Types.h b/nxcomp/Types.h deleted file mode 100644 index e82664c81..000000000 --- a/nxcomp/Types.h +++ /dev/null @@ -1,271 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Types_H -#define Types_H - -using namespace std; - -#include -#include -#include -#include - -#include "MD5.h" - -// -// This is MD5 length. -// - -#define MD5_LENGTH 16 - -// -// Types of repositories. Replace the original -// clear() methods from STL in order to actually -// free the unused memory. -// - -class Message; - -class T_data : public vector < unsigned char > -{ - public: - - unsigned char *begin() - { - return &*(vector < unsigned char >::begin()); - } - - const unsigned char *begin() const - { - return &*(vector < unsigned char >::begin()); - } - - // Avoid overriding clear() when using libc++. Fiddling with STL internals - // doesn't really seem like a good idea to me anyway. - #ifndef _LIBCPP_VECTOR - void clear() - { - #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) - - #if defined(__GLIBCPP_INTERNAL_VECTOR_H) - - _Destroy(_M_start, _M_finish); - - #else /* #if defined(__GLIBCPP_INTERNAL_VECTOR_H) */ - - destroy(_M_start, _M_finish); - - #endif /* #if defined(__GLIBCPP_INTERNAL_VECTOR_H) */ - - _M_deallocate(_M_start, _M_end_of_storage - _M_start); - - _M_start = _M_finish = _M_end_of_storage = 0; - - #else /* #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) */ - - #if defined(_GLIBCXX_VECTOR) - - _Destroy(this->_M_impl._M_start, this->_M_impl._M_finish); - - _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage - this->_M_impl._M_start); - - this->_M_impl._M_start = this->_M_impl._M_finish = this->_M_impl._M_end_of_storage = 0; - - #else /* #if defined(_GLIBCXX_VECTOR) */ - - destroy(start, finish); - - deallocate(); - - start = finish = end_of_storage = 0; - - #endif /* #if defined(_GLIBCXX_VECTOR) */ - - #endif /* #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) */ - } - #endif /* #ifdef _LIBCPP_VECTOR */ -}; - -class T_messages : public vector < Message * > -{ - public: - - // Avoid overriding clear() when using libc++. Fiddling with STL internals - // doesn't really seem like a good idea to me anyway. - #ifndef _LIBCPP_VECTOR - void clear() - { - #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) - - #if defined(__GLIBCPP_INTERNAL_VECTOR_H) - - _Destroy(_M_start, _M_finish); - - #else /* #if defined(__GLIBCPP_INTERNAL_VECTOR_H) */ - - destroy(_M_start, _M_finish); - - #endif /* #if defined(__GLIBCPP_INTERNAL_VECTOR_H) */ - - _M_deallocate(_M_start, _M_end_of_storage - _M_start); - - _M_start = _M_finish = _M_end_of_storage = 0; - - #else /* #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) */ - - #if defined(_GLIBCXX_VECTOR) - - _Destroy(this->_M_impl._M_start, this->_M_impl._M_finish); - - _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage - this->_M_impl._M_start); - - this->_M_impl._M_start = this->_M_impl._M_finish = this->_M_impl._M_end_of_storage = 0; - - #else /* #if defined(_GLIBCXX_VECTOR) */ - - destroy(start, finish); - - deallocate(); - - start = finish = end_of_storage = 0; - - #endif /* #if defined(_GLIBCXX_VECTOR) */ - - #endif /* #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) */ - } - #endif /* #ifndef _LIBCPP_VECTOR */ -}; - -typedef md5_byte_t * T_checksum; - -struct T_less -{ - bool operator()(T_checksum a, T_checksum b) const - { - return (memcmp(a, b, MD5_LENGTH) < 0); - } -}; - -typedef map < T_checksum, int, T_less > T_checksums; - -class Split; - -typedef list < Split * > T_splits; - -class File; - -struct T_older -{ - bool operator()(File *a, File *b) const; -}; - -typedef set < File *, T_older > T_files; - -typedef list < int > T_list; - -// -// Used to accommodate data to be read and -// written to a socket. -// - -typedef struct -{ - T_data data_; - int length_; - int start_; -} -T_buffer; - -// -// The message store operation that was -// executed for the message. The channels -// use these values to determine how to -// handle the message after it has been -// received at the decoding side. -// - -// Since ProtoStep8 (#issue 108) -enum T_store_action -{ - is_hit, - is_added, - is_discarded, - is_removed -}; - -// Since ProtoStep8 (#issue 108) -#define IS_HIT is_hit -#define IS_ADDED is_added - -enum T_checksum_action -{ - use_checksum, - discard_checksum -}; - -enum T_data_action -{ - use_data, - discard_data -}; - -// -// Message is going to be weighted for -// deletion at insert or cleanup time? -// - -enum T_rating -{ - rating_for_insert, - rating_for_clean -}; - -// -// How to handle the writes to the X -// and proxy connections. -// - -enum T_write -{ - write_immediate, - write_delayed -}; - -enum T_flush -{ - flush_if_needed, - flush_if_any -}; - -// -// This is the value to indicate an -// invalid position in the message -// store. -// - -static const int nothing = -1; - -#endif /* Types_H */ diff --git a/nxcomp/Unpack.cpp b/nxcomp/Unpack.cpp deleted file mode 100644 index 50ae890b6..000000000 --- a/nxcomp/Unpack.cpp +++ /dev/null @@ -1,1510 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Misc.h" -#include "Unpack.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -// -// Used for the ZLIB decompression -// of RGB, alpha and colormap data. -// - -z_stream unpackStream; - -static int unpackInitialized; - -int Unpack8To8(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack8To8(T_colormap *colormap, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack8To16(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack8To16(T_colormap *colormap, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack8To24(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack8To24(T_colormap *colormap, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack8To32(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack8To32(T_colormap *colormap, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack15To16(const unsigned char *data, unsigned char *out, - unsigned char *end); - -int Unpack15To24(const unsigned char *data, unsigned char *out, - unsigned char *end); - -int Unpack15To32(const unsigned char *data, unsigned char *out, - unsigned char *end); - -int Unpack16To16(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack16To16(const unsigned char *data, unsigned char *out, - unsigned char *end, int imageByteOrder); - -int Unpack16To24(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack16To24(const unsigned char *data, unsigned char *out, - unsigned char *end, int imageByteOrder); - -int Unpack16To32(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack16To32(const unsigned char *data, unsigned char *out, - unsigned char *end, int imageByteOrder); - -int Unpack24To24(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack24To24(const unsigned char *data, unsigned char *out, - unsigned char *end); - -int Unpack24To32(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - -int Unpack24To32(const unsigned char *data, unsigned char *out, unsigned char *end); - -int Unpack32To32(const T_colormask *colormask, const unsigned int *data, - unsigned int *out, unsigned int *end); - - -void UnpackInit() -{ - if (unpackInitialized == 0) - { - unpackStream.zalloc = (alloc_func) 0; - unpackStream.zfree = (free_func) 0; - unpackStream.opaque = (voidpf) 0; - - unpackStream.next_in = (Bytef *) 0; - unpackStream.avail_in = 0; - - int result = inflateInit2(&unpackStream, 15); - - if (result != Z_OK) - { - #ifdef PANIC - *logofs << "UnpackInit: PANIC! Cannot initialize the Z stream " - << "for decompression. Error is '" << zError(result) - << "'.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Cannot initialize the Z stream for " - << "decompression. Error is '" << zError(result) - << "'.\n"; - } - else - { - unpackInitialized = 1; - } - } -} - -void UnpackDestroy() -{ - if (unpackInitialized == 1) - { - inflateEnd(&unpackStream); - - unpackInitialized = 0; - } -} - -// -// Get bits per pixel set by client -// according to display geometry. -// - -int UnpackBitsPerPixel(T_geometry *geometry, unsigned int depth) -{ - switch (depth) - { - case 1: - { - return geometry -> depth1_bpp; - } - case 4: - { - return geometry -> depth4_bpp; - } - case 8: - { - return geometry -> depth8_bpp; - } - case 15: - case 16: - { - return geometry -> depth16_bpp; - } - case 24: - { - return geometry -> depth24_bpp; - } - case 32: - { - return geometry -> depth32_bpp; - } - default: - { - return 0; - } - } -} - -int Unpack8To8(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack8To8: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - memcpy(out, data, end - out); - - return 1; -} - -int Unpack8To16(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack8To16: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - unsigned short *out16 = (unsigned short *) out; - unsigned short *end16 = (unsigned short *) end; - - while (out16 < end16) - { - if (*data == 0) - { - *out16 = 0x0; - } - else if (*data == 0xff) - { - *out16 = 0xffff; - } - else - { - // - // Pixel layout: - // - // 8bits 00RRGGBB -> 16bits RR000GG0 000BB000. - // - - *out16 = (((((*data & 0x30) << 2) | colormask -> correction_mask) << 8) & 0xf800) | - (((((*data & 0xc) << 4) | colormask -> correction_mask) << 3) & 0x7e0) | - (((((*data & 0x3) << 6) | colormask -> correction_mask) >> 3) & 0x1f); - } - - out16++; - data++; - } - - return 1; -} - -int Unpack8To24(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack8To24: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - while (out < (end - 2)) - { - if (*data == 0x00) - { - out[0] = out[1] = out[2] = 0x00; - } - else if (*data == 0xff) - { - out[0] = out[1] = out[2] = 0xff; - } - else - { - // - // Pixel layout: - // - // 8bits 00RRGGBB -> 24bits RR000000 GG00000 BB000000. - // - - out[0] = (((*data & 0x30) << 2) | colormask -> correction_mask); - out[1] = (((*data & 0x0c) << 4) | colormask -> correction_mask); - out[2] = (((*data & 0x03) << 6) | colormask -> correction_mask); - } - - out += 3; - data += 1; - } - - return 1; -} - -int Unpack8To32(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack8To32: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - unsigned int *out32 = (unsigned int *) out; - unsigned int *end32 = (unsigned int *) end; - - while (out32 < end32) - { - if (*data == 0) - { - *out32 = 0x0; - } - else if (*data == 0xff) - { - *out32 = 0xffffff; - } - else - { - *out32 = ((((*data & 0x30) << 2) | colormask -> correction_mask) << 16) | - ((((*data & 0xc) << 4) | colormask -> correction_mask) << 8) | - (((*data & 0x3) << 6) | colormask -> correction_mask); - } - - out32++; - data++; - } - - return 1; -} - -int Unpack8(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size) -{ - int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); - - int (*unpack)(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - - switch (dst_bpp) - { - case 8: - { - unpack = Unpack8To8; - - break; - } - case 16: - { - unpack = Unpack8To16; - - break; - } - case 24: - { - unpack = Unpack8To24; - - break; - } - case 32: - { - unpack = Unpack8To32; - - break; - } - default: - { - #ifdef PANIC - *logofs << "Unpack8: PANIC! Bad destination bits per pixel " - << dst_bpp << ". Only 16/24/32 are supported.\n" - << logofs_flush; - #endif - - return -1; - } - } - - if (dst_bpp == 24) - { - unsigned char *dst_end = dst_data; - - #ifdef TEST - *logofs << "Unpack8: Handling 24 bits with dst_size " - << dst_size << ".\n" << logofs_flush; - #endif - - for (int y = 0; y < dst_height; y++) - { - dst_data = dst_end; - - dst_end += RoundUp4(dst_width * 3); - - (*unpack)(colormask, src_data, dst_data, dst_end); - - src_data += src_width; - } - } - else - { - unsigned char *dst_end = dst_data + dst_size; - - (*unpack)(colormask, src_data, dst_data, dst_end); - } - - return 1; -} - -int Unpack16To16(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack16To16: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - if (colormask -> correction_mask) - { - unsigned short *data16 = (unsigned short *) data; - - unsigned short *out16 = (unsigned short *) out; - unsigned short *end16 = (unsigned short *) end; - - while (out16 < end16) - { - if (*data16 == 0x0000) - { - *out16 = 0x0000; - } - else if (*data16 == 0xffff) - { - *out16 = 0xffff; - } - else - { - // - // Pixel layout: - // - // 16bit RRRRRGGG GG0BBBBB -> RRRRRGGG GGGBBBBB. - // - - *out16 = (((((*data16 & 0xf100) >> 8) | colormask -> correction_mask) << 8) & 0xf800) | - (((((*data16 & 0x7c0) >> 3) | colormask -> correction_mask) << 3) & 0x7e0) | - (((((*data16 & 0x1f) << 3) | colormask -> correction_mask) >> 3) & 0x1f); - } - - out16++; - data16++; - } - } - else - { - #ifdef TEST - *logofs << "Unpack16To16: Using bitwise copy due to null correction mask.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) out, (unsigned char *) data, end - out); - } - - return 1; -} - -int Unpack16To24(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack16To24: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - unsigned short *data16 = (unsigned short *) data; - - - while (out < end - 2) - { - if (*data16 == 0x0) - { - out[0] = 0x00; - out[1] = 0x00; - out[2] = 0x00; - } - else if (*data16 == 0xffff) - { - out[0] = 0xff; - out[1] = 0xff; - out[2] = 0xff; - } - else - { - #ifdef TEST - *logofs << "Unpack16To24: Pixel [" << *data16 << "]\n" - << logofs_flush; - #endif - - // - // Pixel layout: - // - // 16bit 0RRRRRGG GGGBBBBB -> 24 bit RRRRR000 GGGGG000 BBBBB000 - // - - out[0] = (((*data16 & 0x7c00) >> 7) | colormask -> correction_mask); - out[1] = (((*data16 & 0x03e0) >> 2) | colormask -> correction_mask); - out[2] = (((*data16 & 0x001f) << 3) | colormask -> correction_mask); - } - - out += 3; - data16 += 1; - } - - return 1; -} - -int Unpack16To32(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack16To32: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - unsigned short *data16 = (unsigned short *) data; - - unsigned int *out32 = (unsigned int *) out; - unsigned int *end32 = (unsigned int *) end; - - while (out32 < end32) - { - if (*data16 == 0x0) - { - *out32 = 0x0; - } - else if (*data16 == 0xffff) - { - *out32 = 0xffffff; - } - else - { - *out32 = ((((*data16 & 0x7c00) >> 7) | colormask -> correction_mask) << 16) | - ((((*data16 & 0x3e0) >> 2) | colormask -> correction_mask) << 8) | - (((*data16 & 0x1f) << 3) | colormask -> correction_mask); - } - - out32++; - data16++; - } - - return 1; -} - -int Unpack16(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size) -{ - int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); - - int (*unpack)(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - - switch (dst_bpp) - { - case 16: - { - unpack = Unpack16To16; - - break; - } - case 24: - { - unpack = Unpack16To24; - - break; - } - case 32: - { - unpack = Unpack16To32; - - break; - } - default: - { - #ifdef PANIC - *logofs << "Unpack16: PANIC! Bad destination bits per pixel " - << dst_bpp << ". Only 24/32 are supported.\n" - << logofs_flush; - #endif - - return -1; - } - } - - if (dst_bpp == 24) - { - unsigned char *dst_end = dst_data; - - for (int y = 0; y < dst_height; y++) - { - dst_data = dst_end; - - dst_end += RoundUp4(dst_width * 3); - - (*unpack)(colormask, src_data, dst_data, dst_end); - - src_data += (src_width * 2); - } - - } - else - { - unsigned char *dst_end = dst_data + dst_size; - - (*unpack)(colormask, src_data, dst_data, dst_end); - } - - return 1; -} - -int Unpack24To24(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack24To24: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - if (colormask -> correction_mask) - { - while (out < end) - { - if (data[0] == 0x00 && - data[1] == 0x00 && - data[2] == 0x00) - { - out[0] = out[1] = out[2] = 0x00; - } - else if (data[0] == 0xff && - data[1] == 0xff && - data[2] == 0xff) - { - out[0] = out[1] = out[2] = 0xff; - } - else - { - out[0] = (data[0] | colormask -> correction_mask); - out[1] = (data[1] | colormask -> correction_mask); - out[2] = (data[2] | colormask -> correction_mask); - } - - out += 3; - data += 3; - } - } - else - { - #ifdef TEST - *logofs << "Unpack24To24: Using bitwise copy due to null correction mask.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) out, (unsigned char *) data, end - out); - } - - return 1; -} - -int Unpack24To32(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack24To32: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - unsigned int *out32 = (unsigned int *) out; - unsigned int *end32 = (unsigned int *) end; - - while (out32 < end32) - { - if (colormask -> color_mask == 0xff) - { - *out32 = (data[0] << 16) | (data[1] << 8) | data[2]; - } - else - { - if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x0) - { - *out32 = 0x0; - } - else if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) - { - *out32 = 0xffffff; - } - else - { - *out32 = (((unsigned int) data[0] | colormask -> correction_mask) << 16) | - (((unsigned int) data[1] | colormask -> correction_mask) << 8) | - ((unsigned int) data[2] | colormask -> correction_mask); - } - } - - out32 += 1; - data += 3; - } - - return 1; -} - -int Unpack24(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size) -{ - int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); - - int (*unpack)(const T_colormask *colormask, const unsigned char *data, - unsigned char *out, unsigned char *end); - - switch (dst_bpp) - { - case 24: - { - unpack = Unpack24To24; - - break; - } - case 32: - { - unpack = Unpack24To32; - - break; - } - default: - { - #ifdef PANIC - *logofs << "Unpack24: PANIC! Bad destination bits per pixel " - << dst_bpp << ". Only 32 is supported.\n" - << logofs_flush; - #endif - - return -1; - } - } - - if (dst_bpp == 24) - { - unsigned char *dst_end; - unsigned long scanline_size = RoundUp4(dst_width * dst_bpp / 8); - - dst_end = dst_data; - - #ifdef TEST - *logofs << "Unpack24: Handling 24 bits with dst_height " - << dst_height << " scanline_size " << scanline_size - << " dst_size " << dst_size << ".\n" << logofs_flush; - #endif - - for (int y = 0; y < dst_height; y++) - { - dst_data = dst_end; - - dst_end += scanline_size; - - (*unpack)(colormask, src_data, dst_data, dst_end); - - src_data += scanline_size; - } - } - else - { - unsigned char *dst_end = dst_data + dst_size; - - (*unpack)(colormask, src_data, dst_data, dst_end); - } - - return 1; -} - -int Unpack8To8(T_colormap *colormap, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack8To8: Unpacking " << end - out - << " bytes of colormapped data.\n" - << logofs_flush; - #endif - - while (out < end) - { - *(out++) = (unsigned char) colormap -> data[*(data++)]; - } - - return 1; -} - -int Unpack8To16(T_colormap *colormap, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack8To16: Unpacking " << end - out - << " bytes of colormapped data.\n" - << logofs_flush; - #endif - - unsigned short *out16 = (unsigned short *) out; - unsigned short *end16 = (unsigned short *) end; - - while (out16 < end16) - { - *(out16++) = (unsigned short) colormap -> data[*(data++)]; - } - - return 1; -} - -int Unpack8To24(T_colormap *colormap, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack8To24: Unpacking " << end - out - << " bytes of colormapped data.\n" - << logofs_flush; - #endif - - unsigned int value; - - while (out < end) - { - value = colormap -> data[*(data++)]; - - *(out++) = value; - *(out++) = value >> 8; - *(out++) = value >> 16; - } - - return 1; -} - -int Unpack8To32(T_colormap *colormap, const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack8To32: Unpacking " << end - out - << " bytes of colormapped data.\n" - << logofs_flush; - #endif - - unsigned int *out32 = (unsigned int *) out; - unsigned int *end32 = (unsigned int *) end; - - while (out32 < end32) - { - *(out32++) = colormap -> data[*(data++)]; - } - - return 1; -} - -int Unpack8(T_geometry *geometry, T_colormap *colormap, int src_depth, int src_width, int src_height, - unsigned char *src_data, int src_size, int dst_depth, int dst_width, - int dst_height, unsigned char *dst_data, int dst_size) -{ - if (src_depth != 8) - { - #ifdef PANIC - *logofs << "Unpack8: PANIC! Cannot unpack colormapped image of source depth " - << src_depth << ".\n" << logofs_flush; - #endif - - return -1; - } - - int (*unpack)(T_colormap *colormap, const unsigned char *data, - unsigned char *out, unsigned char *end); - - int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); - - switch (dst_bpp) - { - case 8: - { - unpack = Unpack8To8; - - break; - } - case 16: - { - unpack = Unpack8To16; - - break; - } - case 24: - { - unpack = Unpack8To24; - - break; - } - case 32: - { - unpack = Unpack8To32; - - break; - } - default: - { - #ifdef PANIC - *logofs << "Unpack8: PANIC! Bad destination bits per pixel " - << dst_bpp << ". Only 8/16/24/32 are supported.\n" - << logofs_flush; - #endif - - return -1; - } - } - - if (src_width == dst_width && - src_height == dst_height) - { - unsigned char *dst_end = dst_data + dst_size; - - (*unpack)(colormap, src_data, dst_data, dst_end); - } - else if (src_width >= dst_width && - src_height >= dst_height) - { - unsigned char *dst_end = dst_data; - - for (int y = 0; y < dst_height; y++) - { - dst_data = dst_end; - - dst_end += RoundUp4(dst_width * dst_bpp / 8); - - (*unpack)(colormap, src_data, dst_data, dst_end); - - src_data += src_width; - } - } - else - { - #ifdef PANIC - *logofs << "Unpack8: PANIC! Cannot unpack image. " - << "Destination area " << dst_width << "x" - << dst_height << " is not fully contained in " - << src_width << "x" << src_height << " source.\n" - << logofs_flush; - #endif - - return -1; - } - - return 1; -} - -int Unpack15To16(const unsigned char *data, unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack15To16: Unpacking " << end - out - << " bytes of colormapped data.\n" - << logofs_flush; - #endif - - unsigned short *data16 = (unsigned short *) data; - unsigned short *out16 = (unsigned short *) out; - unsigned short *end16 = (unsigned short *) end; - - while (out16 < end16) - { - if (*data16 == 0x0) - { - *out16 = 0x0; - } - else if (*data16 == 0x7fff) - { - *out16 = 0xffff; - } - else - { - #ifdef TEST - *logofs << "Unpack15To16: Pixel [" << *data16 << "]\n" - << logofs_flush; - #endif - - *out16 = ((*data16 & 0x7ff0) << 1) | - (*data16 & 0x001f); - } - - out16 += 1; - data16 += 1; - } - - return 1; -} - -int Unpack15To24(const unsigned char *data, unsigned char *out, unsigned char *end) - -{ - #ifdef TEST - *logofs << "Unpack15To24: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - unsigned short *data16 = (unsigned short *) data; - - while (out < end - 2) - { - if (*data16 == 0x0) - { - out[0] = 0x00; - out[1] = 0x00; - out[2] = 0x00; - } - else if (*data16 == 0x7fff) - { - out[0] = 0xff; - out[1] = 0xff; - out[2] = 0xff; - } - else - { - #ifdef TEST - *logofs << "Unpack15To24: Pixel [" << *data16 << "]\n" - << logofs_flush; - #endif - - out[0] = ((*data16 >> 7) & 0xf8) | ((*data16 >> 12) & 0x07); - out[1] = ((*data16 >> 2) & 0xf8) | ((*data16 >> 8) & 0x07); - out[2] = ((*data16 << 3) & 0xf8) | ((*data16 >> 2) & 0x07); - } - - out += 3; - data16 += 1; - } - - return 1; -} - -int Unpack15To32(const unsigned char *data, unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack15To32: Unpacking " << end - out - << " bytes of data.\n" - << logofs_flush; - #endif - - unsigned short *data16 = (unsigned short *) data; - unsigned int *out32 = (unsigned int *) out; - unsigned int *end32 = (unsigned int *) end; - - while (out32 < end32) - { - if (*data16 == 0x0) - { - *out32 = 0x0; - } - else if (*data16 == 0xffff) - { - *out32 = 0xffffff; - } - else - { - *out32 = ((((*data16 >> 7) & 0xf8) | ((*data16 >> 12) & 0x07)) << 16) | - ((((*data16 >> 2) & 0xf8) | ((*data16 >> 8) & 0x07)) << 8) | - (((*data16 << 3) & 0xf8) | ((*data16 >> 2) & 0x07)); - } - - out32++; - data16++; - } - - return 1; -} - -int Unpack15(T_geometry *geometry, int src_depth, int src_width, int src_height, - unsigned char *src_data, int src_size, int dst_depth, int dst_width, - int dst_height, unsigned char *dst_data, int dst_size) -{ - if (src_depth != 16) - { - #ifdef PANIC - *logofs << "Unpack15: PANIC! Cannot unpack colormapped image of source depth " - << src_depth << ".\n" << logofs_flush; - #endif - - return -1; - } - - int (*unpack)(const unsigned char *data, unsigned char *out, unsigned char *end); - - int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); - - switch (dst_bpp) - { - case 16: - { - unpack = Unpack15To16; - - break; - } - case 24: - { - unpack = Unpack15To24; - - break; - } - case 32: - { - unpack = Unpack15To32; - - break; - } - default: - { - #ifdef PANIC - *logofs << "Unpack15: PANIC! Bad destination bits per pixel " - << dst_bpp << ". Only 16/24/32 are supported.\n" - << logofs_flush; - #endif - - return -1; - } - } - - if (src_width == dst_width && src_height == dst_height) - { - unsigned char *dst_end = dst_data + dst_size; - - (*unpack)(src_data, dst_data, dst_end); - } - else if (src_width >= dst_width && src_height >= dst_height) - { - unsigned char *dst_end = dst_data; - - for (int y = 0; y < dst_height; y++) - { - dst_data = dst_end; - dst_end += RoundUp4(dst_width * dst_bpp / 8); - - (*unpack)(src_data, dst_data, dst_end); - - src_data += src_width * 2; - } - } - else - { - #ifdef PANIC - *logofs << "Unpack15: PANIC! Cannot unpack image. " - << "Destination area " << dst_width << "x" - << dst_height << " is not fully contained in " - << src_width << "x" << src_height << " source.\n" - << logofs_flush; - #endif - - return -1; - } - - return 1; -} - -int Unpack16To16(const unsigned char *data, unsigned char *out, - unsigned char *end, int imageByteOrder) -{ - #ifdef TEST - *logofs << "Unpack16To16: Unpacking " << end - out - << " bytes of colormapped data.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) out, (unsigned char *) data, end - out); - - return 1; -} - -int Unpack16To24(const unsigned char *data, unsigned char *out, - unsigned char *end, int imageByteOrder) - -{ - #ifdef TEST - *logofs << "Unpack16To24: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - unsigned short *data16 = (unsigned short *) data; - - while (out < end - 2) - { - if (*data16 == 0x0) - { - out[0] = 0x00; - out[1] = 0x00; - out[2] = 0x00; - } - else if (*data16 == 0xffff) - { - out[0] = 0xff; - out[1] = 0xff; - out[2] = 0xff; - } - else - { - #ifdef TEST - *logofs << "Unpack16To24: Pixel [" << *data16 << "]\n" - << logofs_flush; - #endif - - out[0] = ((*data16 >> 8) & 0xf8) | ((*data16 >> 13) & 0x07); - out[1] = ((*data16 >> 3) & 0xfc) | ((*data16 >> 9) & 0x03); - out[2] = ((*data16 << 3) & 0xf8) | ((*data16 >> 2) & 0x07); - } - - out += 3; - data16 += 1; - } - - return 1; -} - - -int Unpack16To32(const unsigned char *data, unsigned char *out, - unsigned char *end, int imageByteOrder) -{ - #ifdef TEST - *logofs << "Unpack16To32: Unpacking " << end - out - << " bytes of data.\n" - << logofs_flush; - #endif - - unsigned short *data16 = (unsigned short *) data; - unsigned int *out32 = (unsigned int *) out; - unsigned int *end32 = (unsigned int *) end; - - unsigned short pixel16; - unsigned int pixel32; - - while (out32 < end32) - { - - pixel16 = GetUINT((unsigned char *)data16, 0); - - if (pixel16 == 0x0) - { - PutULONG(0x0, (unsigned char *) out32, imageByteOrder); - } - else if (pixel16 == 0xffff) - { - PutULONG(0xffffff, (unsigned char *) out32, imageByteOrder); - } - else - { - pixel32 = ((((pixel16 >> 8) & 0xf8) | ((pixel16 >> 13) & 0x07)) << 16) | - ((((pixel16 >> 3) & 0xfc) | ((pixel16 >> 9) & 0x03)) << 8) | - (((pixel16 << 3) & 0xf8) | ((pixel16 >> 2) & 0x07)); - - PutULONG(pixel32, (unsigned char *) out32, imageByteOrder); - } - - out32++; - data16++; - } - return 1; -} - -int Unpack16(T_geometry *geometry, int src_depth, int src_width, int src_height, - unsigned char *src_data, int src_size, int dst_depth, int dst_width, - int dst_height, unsigned char *dst_data, int dst_size) -{ - int imageByteOrder = geometry -> image_byte_order; - - if (src_depth != 16) - { - #ifdef PANIC - *logofs << "Unpack16: PANIC! Cannot unpack colormapped image of source depth " - << src_depth << ".\n" << logofs_flush; - #endif - - return -1; - } - - int (*unpack)(const unsigned char *data, unsigned char *out, - unsigned char *end, int imageByteOrder); - - int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); - - switch (dst_bpp) - { - case 16: - { - unpack = Unpack16To16; - - break; - } - case 24: - { - unpack = Unpack16To24; - - break; - } - case 32: - { - unpack = Unpack16To32; - - break; - } - default: - { - #ifdef PANIC - *logofs << "Unpack16: PANIC! Bad destination bits per pixel " - << dst_bpp << ". Only 16/24/32 are supported.\n" - << logofs_flush; - #endif - - return -1; - } - } - - if (src_width == dst_width && src_height == dst_height) - { - unsigned char *dst_end = dst_data + dst_size; - - (*unpack)(src_data, dst_data, dst_end, imageByteOrder); - } - else if (src_width >= dst_width && src_height >= dst_height) - { - unsigned char *dst_end = dst_data; - - for (int y = 0; y < dst_height; y++) - { - dst_data = dst_end; - dst_end += RoundUp4(dst_width * dst_bpp / 8); - - (*unpack)(src_data, dst_data, dst_end, imageByteOrder); - - src_data += src_width * 2; - } - } - else - { - #ifdef PANIC - *logofs << "Unpack16: PANIC! Cannot unpack image. " - << "Destination area " << dst_width << "x" - << dst_height << " is not fully contained in " - << src_width << "x" << src_height << " source.\n" - << logofs_flush; - #endif - - return -1; - } - - return 1; -} - -int Unpack24To24(const unsigned char *data, - unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack124To24: Unpacking " << end - out - << " bytes of colormapped data.\n" - << logofs_flush; - #endif - - while (out < end) - { - *(out++) = *(data++); - } - - return 1; -} - -int Unpack24To32(const unsigned char *data, unsigned char *out, unsigned char *end) -{ - #ifdef TEST - *logofs << "Unpack24To32: Unpacking " << end - out - << " bytes of colormapped data.\n" - << logofs_flush; - #endif - - unsigned int *out32 = (unsigned int *) out; - unsigned int *end32 = (unsigned int *) end; - - while (out32 < end32) - { - if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x0) - { - *out32 = 0x0; - } - else if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) - { - *out32 = 0xffffff; - } - else - { - *out32 = (data[2] << 16) | (data[1] << 8) | data[0]; - } - - out32 += 1; - data += 3; - } - - return 1; -} - -int Unpack24(T_geometry *geometry, int src_depth, int src_width, int src_height, - unsigned char *src_data, int src_size, int dst_depth, int dst_width, - int dst_height, unsigned char *dst_data, int dst_size) - -{ - if (src_depth != 24) - { - #ifdef PANIC - *logofs << "Unpack24: PANIC! Cannot unpack colormapped image of source depth " - << src_depth << ".\n" << logofs_flush; - #endif - - return -1; - } - - int (*unpack)(const unsigned char *data, unsigned char *out, unsigned char *end); - - int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); - - switch (dst_bpp) - { - case 24: - { - unpack = Unpack24To24; - - break; - } - case 32: - { - unpack = Unpack24To32; - - break; - } - default: - { - #ifdef PANIC - *logofs << "Unpack24: PANIC! Bad destination bits per pixel " - << dst_bpp << ". Only 24/32 are supported.\n" - << logofs_flush; - #endif - - return -1; - } - } - - if (src_width == dst_width && src_height == dst_height) - { - unsigned char *dst_end = dst_data + dst_size; - - (*unpack)(src_data, dst_data, dst_end); - } - else if (src_width >= dst_width && src_height >= dst_height) - { - unsigned char *dst_end = dst_data; - - for (int y = 0; y < dst_height; y++) - { - dst_data = dst_end; - dst_end += RoundUp4(dst_width * dst_bpp / 8); - - (*unpack)(src_data, dst_data, dst_end); - - src_data += src_width * 3; - } - } - else - { - #ifdef PANIC - *logofs << "Unpack24: PANIC! Cannot unpack image. " - << "Destination area " << dst_width << "x" - << dst_height << " is not fully contained in " - << src_width << "x" << src_height << " source.\n" - << logofs_flush; - #endif - - return -1; - } - - return 1; -} - -int Unpack32To32(const T_colormask *colormask, const unsigned int *data, - unsigned int *out, unsigned int *end) -{ - #ifdef TEST - *logofs << "Unpack32To32: Unpacking " << end - out - << " bytes of data.\n" << logofs_flush; - #endif - - if (colormask -> correction_mask) - { - while (out < end) - { - if (*data == 0x00000000) - { - *out = 0x00000000; - } - else if (*data == 0xFFFFFFFF) - { - *out = 0xFFFFFFFF; - } - else - { - *out = *data | ((colormask -> correction_mask << 16) | - (colormask -> correction_mask << 8) | - colormask -> correction_mask); - } - - out += 1; - data += 1; - } - } - else - { - #ifdef TEST - *logofs << "Unpack32To32: Using bitwise copy due to null correction mask.\n" - << logofs_flush; - #endif - - memcpy((unsigned char *) out, (unsigned char *) data, end - out); - } - - return 1; -} diff --git a/nxcomp/Unpack.h b/nxcomp/Unpack.h deleted file mode 100644 index faaa41d82..000000000 --- a/nxcomp/Unpack.h +++ /dev/null @@ -1,149 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Unpack_H -#define Unpack_H - -#include "NXpack.h" - -#include "Z.h" - -#define LSBFirst 0 -#define MSBFirst 1 - -#define SPLIT_PATTERN 0x88 - -typedef ColorMask T_colormask; - -// -// Pixel geometry of channel's display. -// - -typedef struct -{ - unsigned int depth1_bpp; - unsigned int depth4_bpp; - unsigned int depth8_bpp; - unsigned int depth16_bpp; - unsigned int depth24_bpp; - unsigned int depth32_bpp; - - unsigned int red_mask; - unsigned int green_mask; - unsigned int blue_mask; - - unsigned int image_byte_order; - unsigned int bitmap_bit_order; - unsigned int scanline_unit; - unsigned int scanline_pad; - -} T_geometry; - -// -// Colormap is used to remap colors -// from source to destination depth. -// - -typedef struct -{ - unsigned int entries; - unsigned int *data; - -} T_colormap; - -// -// Alpha channel data is added to 32 -// bits images at the time they are -// unpacked. -// - -typedef struct -{ - unsigned int entries; - unsigned char *data; - -} T_alpha; - -// -// The ZLIB stream structure used for -// the decompression. -// - -extern z_stream unpackStream; - -// -// Initialize the ZLIB stream used for -// decompression. -// - -void UnpackInit(); - -// -// Free the ZLIB stream. -// - -void UnpackDestroy(); - -// -// Get the destination bits per pixel -// based on the drawable depth. -// - -int UnpackBitsPerPixel(T_geometry *geometry, unsigned int depth); - -// -// Unpack the source data into the X -// bitmap. -// - -int Unpack8(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size); - -int Unpack16(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size); - -int Unpack24(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size); - -int Unpack8(T_geometry *geometry, T_colormap *colormap, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size); - -int Unpack15(T_geometry *geometry, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size); - -int Unpack16(T_geometry *geometry, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size); - -int Unpack24(T_geometry *geometry, int src_depth, int src_width, - int src_height, unsigned char *src_data, int src_size, int dst_depth, - int dst_width, int dst_height, unsigned char *dst_data, int dst_size); - -#endif /* Unpack_H */ diff --git a/nxcomp/Vars.c b/nxcomp/Vars.c deleted file mode 100644 index 685969677..000000000 --- a/nxcomp/Vars.c +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include "NXvars.h" - -/* - * Allocate here instances of variables and - * pointers declared in NXvars.h. - */ - -int _NXHandleDisplayError = 0; - -NXDisplayErrorPredicate _NXDisplayErrorFunction = NULL; - -int _NXUnsetLibraryPath = 0; - -NXLostSequenceHandler _NXLostSequenceFunction = NULL; - -NXDisplayBlockHandler _NXDisplayBlockFunction = NULL; -NXDisplayWriteHandler _NXDisplayWriteFunction = NULL; -NXDisplayFlushHandler _NXDisplayFlushFunction = NULL; -NXDisplayStatisticsHandler _NXDisplayStatisticsFunction = NULL; - -#ifdef __cplusplus -} -#endif diff --git a/nxcomp/Version.c b/nxcomp/Version.c deleted file mode 100644 index ff1793434..000000000 --- a/nxcomp/Version.c +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2015 Qindel Formacion y Servicios SL. */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License Version 2, as */ -/* published by the Free Software Foundation. */ -/* */ -/* This program is distributed in the hope that it will be useful, but */ -/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTA- */ -/* BILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ -/* Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, you can request a copy from Qindel */ -/* or write to the Free Software Foundation, Inc., 51 Franklin Street, */ -/* Fifth Floor, Boston, MA 02110-1301 USA. */ -/* */ -/* All rights reserved. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include "NX.h" - - -static int _NXVersionMajor = -1; -static int _NXVersionMinor = -1; -static int _NXVersionPatch = -1; -static int _NXVersionMaintenancePatch = -1; - - -const char* NXVersion() { - const char *version = VERSION; - return version; -} - -void _parseNXVersion() { - char version[32]; - int i; - strcpy(version, VERSION); - - char *value; - /* Reset values to 0 if undefined */ - _NXVersionMajor = _NXVersionMinor = _NXVersionPatch = _NXVersionMaintenancePatch = 0; - - -#define NXVERSIONSEPARATOR "." - value = strtok(version, NXVERSIONSEPARATOR); - - for (i = 0; value != NULL && i < 4; i++) - { - switch (i) - { - case 0: - _NXVersionMajor = atoi(value); - break; - - case 1: - _NXVersionMinor = atoi(value); - break; - - case 2: - _NXVersionPatch = atoi(value); - break; - - case 3: - _NXVersionMaintenancePatch = atoi(value); - break; - } - - value = strtok(NULL, NXVERSIONSEPARATOR); - } -} - -int NXMajorVersion() { - if (_NXVersionMajor == -1) - _parseNXVersion(); - return _NXVersionMajor; -} -int NXMinorVersion() { - if (_NXVersionMinor == -1) - _parseNXVersion(); - return _NXVersionMinor; -} -int NXPatchVersion() { - if (_NXVersionPatch == -1) - _parseNXVersion(); - return _NXVersionPatch; -} -int NXMaintenancePatchVersion() { - if (_NXVersionMaintenancePatch == -1) - _parseNXVersion(); - return _NXVersionMaintenancePatch; -} diff --git a/nxcomp/WriteBuffer.cpp b/nxcomp/WriteBuffer.cpp deleted file mode 100644 index 07d14fc30..000000000 --- a/nxcomp/WriteBuffer.cpp +++ /dev/null @@ -1,496 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include -#include -#include -#include - -#include "Misc.h" -#include "Control.h" - -#include "WriteBuffer.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -WriteBuffer::WriteBuffer() -{ - size_ = WRITE_BUFFER_DEFAULT_SIZE; - buffer_ = new unsigned char[size_]; - length_ = 0; - index_ = NULL; - - scratchLength_ = 0; - scratchBuffer_ = NULL; - scratchOwner_ = 1; - - initialSize_ = WRITE_BUFFER_DEFAULT_SIZE; - thresholdSize_ = WRITE_BUFFER_DEFAULT_SIZE << 1; - maximumSize_ = WRITE_BUFFER_DEFAULT_SIZE << 4; - - #ifdef VALGRIND - - memset(buffer_, '\0', size_); - - #endif -} - -WriteBuffer::~WriteBuffer() -{ - if (scratchOwner_ == 1 && - scratchBuffer_ != NULL) - { - delete [] scratchBuffer_; - } - - delete [] buffer_; -} - -void WriteBuffer::setSize(unsigned int initialSize, unsigned int thresholdSize, - unsigned int maximumSize) -{ - initialSize_ = initialSize; - thresholdSize_ = thresholdSize; - maximumSize_ = maximumSize; - - #ifdef TEST - *logofs << "WriteBuffer: Set buffer sizes to " - << initialSize_ << "/" << thresholdSize_ - << "/" << maximumSize_ << ".\n" - << logofs_flush; - #endif -} - -void WriteBuffer::partialReset() -{ - if (scratchBuffer_ != NULL) - { - if (scratchOwner_) - { - #ifdef DEBUG - *logofs << "WriteBuffer: Going to delete " - << scratchLength_ << " bytes from the " - << "scratch buffer.\n" << logofs_flush; - #endif - - delete [] scratchBuffer_; - } - - scratchLength_ = 0; - scratchBuffer_ = NULL; - scratchOwner_ = 1; - } - - length_ = 0; - index_ = NULL; - - #ifdef DEBUG - *logofs << "WriteBuffer: Performed partial reset with " - << size_ << " bytes in buffer.\n" - << logofs_flush; - #endif -} - -void WriteBuffer::fullReset() -{ - if (scratchBuffer_ != NULL) - { - if (scratchOwner_ == 1) - { - #ifdef DEBUG - *logofs << "WriteBuffer: Going to delete " - << scratchLength_ << " bytes from the " - << "scratch buffer.\n" << logofs_flush; - #endif - - delete [] scratchBuffer_; - } - - scratchLength_ = 0; - scratchBuffer_ = NULL; - scratchOwner_ = 1; - } - - length_ = 0; - index_ = NULL; - - if (size_ > initialSize_) - { - #ifdef TEST - *logofs << "WriteBuffer: Reallocating a new buffer of " - << initialSize_ << " bytes.\n" << logofs_flush; - #endif - - delete [] buffer_; - - size_ = initialSize_; - - buffer_ = new unsigned char[size_]; - - if (buffer_ == NULL) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't allocate memory for " - << "X messages in context [A].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory for " - << "X messages in context [A].\n"; - - HandleAbort(); - } - - #ifdef VALGRIND - - memset(buffer_, '\0', size_); - - #endif - } - - #ifdef DEBUG - *logofs << "WriteBuffer: Performed full reset with " - << size_ << " bytes in buffer.\n" - << logofs_flush; - #endif -} - -unsigned char *WriteBuffer::addMessage(unsigned int numBytes) -{ - #ifdef DEBUG - *logofs << "WriteBuffer: Adding " << numBytes << " bytes to " - << length_ << " bytes already in buffer.\n" - << logofs_flush; - #endif - - if (numBytes > WRITE_BUFFER_OVERFLOW_SIZE) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't add a message of " - << numBytes << " bytes.\n" << logofs_flush; - - *logofs << "WriteBuffer: PANIC! Assuming error handling " - << "data in context [B].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't add a message of " - << numBytes << " bytes to write buffer.\n"; - - cerr << "Error" << ": Assuming error handling " - << "data in context [B].\n"; - - HandleAbort(); - } - else if (length_ + numBytes > size_) - { - unsigned int newSize = thresholdSize_; - - while (newSize < length_ + numBytes) - { - newSize <<= 1; - - if (newSize > maximumSize_) - { - newSize = length_ + numBytes + initialSize_; - } - } - - #ifdef TEST - *logofs << "WriteBuffer: Growing buffer from " - << size_ << " to " << newSize << " bytes.\n" - << logofs_flush; - #endif - - unsigned int indexOffset = 0; - - if (index_ && *index_) - { - indexOffset = *index_ - buffer_; - } - - size_ = newSize; - - unsigned char *newBuffer = new unsigned char[size_]; - - if (newBuffer == NULL) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't allocate memory for " - << "X messages in context [C].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory for " - << "X messages in context [C].\n"; - - HandleAbort(); - } - - #ifdef TEST - if (newSize >= maximumSize_) - { - *logofs << "WriteBuffer: WARNING! Buffer grown to reach " - << "size of " << newSize << " bytes.\n" - << logofs_flush; - } - #endif - - #ifdef VALGRIND - - memset(newBuffer, '\0', size_); - - #endif - - memcpy(newBuffer, buffer_, length_); - - #ifdef DEBUG - *logofs << "WriteBuffer: Going to delete the " - << "old buffer with new size " << size_ - << ".\n" << logofs_flush; - #endif - - delete [] buffer_; - - buffer_ = newBuffer; - - if (index_ && *index_) - { - *index_ = buffer_ + indexOffset; - } - } - - unsigned char *result = buffer_ + length_; - - length_ += numBytes; - - #ifdef DEBUG - *logofs << "WriteBuffer: Bytes in buffer are " - << length_ << " while size is " << size_ - << ".\n" << logofs_flush; - #endif - - return result; -} - -unsigned char *WriteBuffer::removeMessage(unsigned int numBytes) -{ - #ifdef TEST - *logofs << "WriteBuffer: Removing " << numBytes - << " bytes from buffer.\n" << logofs_flush; - #endif - - if (numBytes > length_) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't remove " - << numBytes << " bytes with only " << length_ - << " bytes in buffer.\n" << logofs_flush; - #endif - - cerr << "Error" << ": Buffer underflow handling " - << "write buffer in context [D].\n"; - - HandleAbort(); - } - - length_ -= numBytes; - - #ifdef TEST - *logofs << "WriteBuffer: Bytes in buffer are now " - << length_ << " while size is " - << size_ << ".\n" << logofs_flush; - #endif - - return (buffer_ + length_); -} - -unsigned char *WriteBuffer::addScratchMessage(unsigned int numBytes) -{ - if (numBytes > WRITE_BUFFER_OVERFLOW_SIZE) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't add a message of " - << numBytes << " bytes.\n" << logofs_flush; - - *logofs << "WriteBuffer: PANIC! Assuming error handling " - << "data in context [E].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't add a message of " - << numBytes << " bytes to write buffer.\n"; - - cerr << "Error" << ": Assuming error handling " - << "data in context [E].\n"; - - HandleAbort(); - } - else if (scratchBuffer_ != NULL) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't add a message of " - << numBytes << " bytes with " << scratchLength_ - << " bytes already in scratch buffer.\n" - << logofs_flush; - - *logofs << "WriteBuffer: PANIC! Assuming error handling " - << "data in context [F].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't add a message of " - << numBytes << " bytes with " << scratchLength_ - << " bytes already in scratch buffer.\n"; - - cerr << "Error" << ": Assuming error handling " - << "data in context [F].\n"; - - HandleAbort(); - } - - #ifdef DEBUG - *logofs << "WriteBuffer: Adding " << numBytes << " bytes " - << "to scratch buffer.\n" << logofs_flush; - #endif - - unsigned char *newBuffer = new unsigned char[numBytes]; - - if (newBuffer == NULL) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't allocate memory for " - << "X messages in context [G].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't allocate memory for " - << "X messages in context [G].\n"; - - HandleAbort(); - } - - #ifdef VALGRIND - - memset(newBuffer, '\0', numBytes); - - #endif - - scratchBuffer_ = newBuffer; - scratchOwner_ = 1; - scratchLength_ = numBytes; - - return newBuffer; -} - -unsigned char *WriteBuffer::addScratchMessage(unsigned char *newBuffer, unsigned int numBytes) -{ - if (numBytes > WRITE_BUFFER_OVERFLOW_SIZE) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't add a message of " - << numBytes << " bytes.\n" << logofs_flush; - - *logofs << "WriteBuffer: PANIC! Assuming error handling " - << "data in context [H].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't add a message of " - << numBytes << " bytes to write buffer.\n"; - - cerr << "Error" << ": Assuming error handling " - << "data in context [H].\n"; - - HandleAbort(); - } - else if (scratchBuffer_ != NULL) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't add a foreign " - << "message of " << numBytes << " bytes with " - << scratchLength_ << " bytes already in " - << "scratch buffer.\n" << logofs_flush; - - *logofs << "WriteBuffer: PANIC! Assuming error handling " - << "data in context [I].\n" << logofs_flush; - #endif - - cerr << "Error" << ": Can't add a foreign message of " - << numBytes << " bytes with " << scratchLength_ - << " bytes already in scratch buffer.\n"; - - cerr << "Error" << ": Assuming error handling " - << "data in context [I].\n"; - - HandleAbort(); - } - - #ifdef DEBUG - *logofs << "WriteBuffer: Adding " << numBytes << " bytes " - << "from a foreign message to scratch buffer.\n" - << logofs_flush; - #endif - - scratchBuffer_ = newBuffer; - scratchLength_ = numBytes; - scratchOwner_ = 0; - - return newBuffer; -} - -void WriteBuffer::removeScratchMessage() -{ - #ifdef TEST - - if (scratchLength_ == 0 || scratchBuffer_ == NULL) - { - #ifdef PANIC - *logofs << "WriteBuffer: PANIC! Can't remove non existent scratch message.\n" - << logofs_flush; - #endif - - cerr << "Error" << ": Can't remove non existent scratch message.\n"; - - HandleAbort(); - } - - *logofs << "WriteBuffer: Removing " << scratchLength_ - << " bytes from scratch buffer.\n" - << logofs_flush; - - #endif - - if (scratchOwner_ == 1) - { - #ifdef DEBUG - *logofs << "WriteBuffer: Going to delete " - << scratchLength_ << " bytes from the " - << "scratch buffer.\n" << logofs_flush; - #endif - - delete [] scratchBuffer_; - } - - scratchLength_ = 0; - scratchBuffer_ = NULL; - scratchOwner_ = 1; -} diff --git a/nxcomp/WriteBuffer.h b/nxcomp/WriteBuffer.h deleted file mode 100644 index ce408e210..000000000 --- a/nxcomp/WriteBuffer.h +++ /dev/null @@ -1,134 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef WriteBuffer_H -#define WriteBuffer_H - -#include "Misc.h" - -#define PANIC -#define WARNING -#undef TEST -#undef DEBUG - -#define WRITE_BUFFER_DEFAULT_SIZE 16384 - -// -// Adjust for the biggest reply that we could receive. -// This is likely to be a reply to a X_ListFonts where -// user has a large amount of installed fonts. -// - -#define WRITE_BUFFER_OVERFLOW_SIZE 4194304 - -class WriteBuffer -{ - public: - - WriteBuffer(); - - ~WriteBuffer(); - - void setSize(unsigned int initialSize, unsigned int thresholdSize, - unsigned int maximumSize); - - unsigned char *addMessage(unsigned int numBytes); - - unsigned char *removeMessage(unsigned int numBytes); - - unsigned char *addScratchMessage(unsigned int numBytes); - - // - // This form allows user to provide its own - // buffer as write buffer's scratch area. - // - - unsigned char *addScratchMessage(unsigned char *newBuffer, unsigned int numBytes); - - void removeScratchMessage(); - - void partialReset(); - - void fullReset(); - - unsigned char *getData() const - { - return buffer_; - } - - unsigned int getLength() const - { - return length_; - } - - unsigned int getAvailable() const - { - return (size_ - length_); - } - - unsigned char *getScratchData() const - { - return scratchBuffer_; - } - - unsigned int getScratchLength() const - { - return scratchLength_; - } - - unsigned int getTotalLength() const - { - return (length_ + scratchLength_); - } - - void registerPointer(unsigned char **pointer) - { - index_ = pointer; - } - - void unregisterPointer() - { - index_ = 0; - } - - private: - - unsigned int size_; - unsigned int length_; - - unsigned char *buffer_; - unsigned char **index_; - - unsigned int scratchLength_; - unsigned char *scratchBuffer_; - - int scratchOwner_; - - unsigned int initialSize_; - unsigned int thresholdSize_; - unsigned int maximumSize_; -}; - -#endif /* WriteBuffer_H */ diff --git a/nxcomp/XidCache.cpp b/nxcomp/XidCache.cpp deleted file mode 100644 index 0f83d388f..000000000 --- a/nxcomp/XidCache.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Control.h" - -#include "XidCache.h" - -XidCache::XidCache() -{ - for (int i = 0; i < 256; i++) - { - base_[i] = new IntCache(8); - } - - slot_ = 0; - last_ = 0; -} - -XidCache::~XidCache() -{ - for (int i = 0; i < 256; i++) - { - delete base_[i]; - } -} diff --git a/nxcomp/XidCache.h b/nxcomp/XidCache.h deleted file mode 100644 index 8a09ef9b1..000000000 --- a/nxcomp/XidCache.h +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef XidCache_H -#define XidCache_H - -#include "IntCache.h" - -class XidCache -{ - friend class EncodeBuffer; - friend class DecodeBuffer; - - public: - - XidCache(); - ~XidCache(); - - private: - - IntCache *base_[256]; - - unsigned int slot_; - unsigned int last_; -}; - -#endif /* XidCache_H */ diff --git a/nxcomp/Z.cpp b/nxcomp/Z.cpp deleted file mode 100644 index 35850b9d0..000000000 --- a/nxcomp/Z.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#include "Z.h" -#include "Misc.h" - -int ZCompress(z_stream *stream, unsigned char *dest, unsigned int *destLen, - const unsigned char *source, unsigned int sourceLen) -{ - // - // Deal with the possible overflow. - // - - if (stream -> total_out & 0x80000000) - { - #ifdef TEST - *logofs << "ZCompress: Reset stream counters with " - << "total in " << stream -> total_in - << " and total out " << stream -> total_out - << ".\n" << logofs_flush; - #endif - - stream -> total_in = 0; - stream -> total_out = 0; - } - - unsigned int saveOut = stream -> total_out; - - stream -> next_in = (Bytef *) source; - stream -> avail_in = sourceLen; - - // - // Check if the source is bigger than - // 64K on 16-bit machine. - // - - #ifdef MAXSEG_64K - - if ((uLong) stream -> avail_in != sourceLen) return Z_BUF_ERROR; - - #endif - - stream -> next_out = dest; - stream -> avail_out = *destLen; - - #ifdef MAXSEG_64K - - if ((uLong) stream -> avail_out != *destLen) return Z_BUF_ERROR; - - #endif - - int result = deflate(stream, Z_FINISH); - - if (result != Z_STREAM_END) - { - deflateReset(stream); - - return (result == Z_OK ? Z_BUF_ERROR : result); - } - - *destLen = stream -> total_out - saveOut; - - result = deflateReset(stream); - - return result; -} - -int ZDecompress(z_stream *stream, unsigned char *dest, unsigned int *destLen, - const unsigned char *source, unsigned int sourceLen) -{ - stream -> next_in = (Bytef *) source; - stream -> avail_in = sourceLen; - - // - // Deal with the possible overflow. - // - - if (stream -> total_out & 0x80000000) - { - #ifdef TEST - *logofs << "ZDecompress: Reset stream counters with " - << "total in " << stream -> total_in - << " and total out " << stream -> total_out - << ".\n" << logofs_flush; - #endif - - stream -> total_in = 0; - stream -> total_out = 0; - } - - unsigned int saveOut = stream -> total_out; - - if (stream -> avail_in != sourceLen) - { - return Z_BUF_ERROR; - } - - stream -> next_out = dest; - stream -> avail_out = *destLen; - - if (stream -> avail_out != *destLen) - { - return Z_BUF_ERROR; - } - - int result = inflate(stream, Z_FINISH); - - if (result != Z_STREAM_END) - { - inflateReset(stream); - - return (result == Z_OK ? Z_BUF_ERROR : result); - } - - *destLen = stream -> total_out - saveOut; - - result = inflateReset(stream); - - return result; -} diff --git a/nxcomp/Z.h b/nxcomp/Z.h deleted file mode 100644 index 3a6d684c2..000000000 --- a/nxcomp/Z.h +++ /dev/null @@ -1,37 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -/* Copyright (c) 2008-2014 Oleksandr Shneyder */ -/* Copyright (c) 2014-2016 Ulrich Sibiller */ -/* Copyright (c) 2014-2016 Mihai Moldovan */ -/* Copyright (c) 2011-2016 Mike Gabriel */ -/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -/* */ -/* NXCOMP, NX protocol compression and NX extensions to this software */ -/* are copyright of the aforementioned persons and companies. */ -/* */ -/* Redistribution and use of the present software is allowed according */ -/* to terms specified in the file LICENSE.nxcomp which comes in the */ -/* source distribution. */ -/* */ -/* All rights reserved. */ -/* */ -/* NOTE: This software has received contributions from various other */ -/* contributors, only the core maintainers and supporters are listed as */ -/* copyright holders. Please contact us, if you feel you should be listed */ -/* as copyright holder, as well. */ -/* */ -/**************************************************************************/ - -#ifndef Z_H -#define Z_H - -#include - -int ZCompress(z_stream *stream, unsigned char *dest, unsigned int *destLen, - const unsigned char *source, unsigned int sourceLen); - -int ZDecompress(z_stream *stream, unsigned char *dest, unsigned int *destLen, - const unsigned char *source, unsigned int sourceLen); - -#endif /* Z_H */ diff --git a/nxcomp/configure.ac b/nxcomp/configure.ac new file mode 100644 index 000000000..87087f32d --- /dev/null +++ b/nxcomp/configure.ac @@ -0,0 +1,83 @@ +# *************************************************************************** +# *** configure.ac for nxcomp *** +# *************************************************************************** + +m4_define([nxcomp_version], m4_esyscmd([tr -d '\n' < VERSION])) + +# Initialize Autoconf +AC_PREREQ(2.60) + +AC_INIT([libXcomp], [nxcomp_version], [https://github.com/ArcticaProject/nx-libs/issues]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_PROG_CXX +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-xz]) + +# Initialize libtool +AC_PROG_LIBTOOL + +COMP_VERSION=nxcomp_version +AC_SUBST([COMP_VERSION]) + +LT_COMP_VERSION=[`echo $COMP_VERSION | sed -r -e 's/^([0-9]+\.[0-9]+\.[0-9]+).*$/\1/' -e 's/\./:/g'`] +AC_SUBST([LT_COMP_VERSION]) + +PKG_CHECK_MODULES(JPEG, libjpeg) +PKG_CHECK_MODULES(PNG, libpng) +PKG_CHECK_MODULES(Z, zlib) + +# Upstream's pkg.m4 (since 0.27) offers this now, but define our own +# compatible version in case the local version of pkgconfig isn't new enough. +# https://bugs.freedesktop.org/show_bug.cgi?id=48743 +m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR], + [AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], + [install directory for nxcompshad.pc pkg-config file])], + [],[with_pkgconfigdir='$(libdir)/pkgconfig']) + AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])]) + +AC_LANG([C++]) +NX_COMPILER_BRAND +NX_COMPILER_FLAGS + +NX_BUILD_ON_CYGWIN32 +NX_BUILD_ON_AMD64 +NX_BUILD_ON_DARWIN +NX_BUILD_ON_SUN +NX_BUILD_ON_FreeBSD + +# Build PIC libraries. + +if test "$CYGWIN32" != yes -a "$DARWIN" != yes; then + CXXFLAGS="$CXXFLAGS -fPIC" + CFLAGS="$CFLAGS -fPIC" +fi + +# On FreeBSD search libraries and includes under /usr/local. + +if test "$FreeBSD" = yes; then + LIBS="$LIBS -L/usr/local/lib" + CPPFLAGS="$CPPFLAGS -I/usr/local/include" +fi + +NX_HAS_INADDRT + +# If in_addr_t is not defined use unsigned int. + +if test "$INADDRT" != yes ; then + echo -e "using unsigned int for type in_addr_t" + CPPFLAGS="$CPPFLAGS -DIN_ADDR_T=unsigned" +else + CPPFLAGS="$CPPFLAGS -DIN_ADDR_T=in_addr_t" +fi + +AC_CONFIG_FILES([ +Makefile +src/Makefile +nxcomp.pc +]) + +AC_OUTPUT diff --git a/nxcomp/configure.in b/nxcomp/configure.in deleted file mode 100644 index 8be604836..000000000 --- a/nxcomp/configure.in +++ /dev/null @@ -1,413 +0,0 @@ -dnl /**************************************************************************/ -dnl /* */ -dnl /* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ -dnl /* Copyright (c) 2008-2014 Oleksandr Shneyder */ -dnl /* Copyright (c) 2014-2016 Ulrich Sibiller */ -dnl /* Copyright (c) 2014-2016 Mihai Moldovan */ -dnl /* Copyright (c) 2011-2016 Mike Gabriel */ -dnl /* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ -dnl /* */ -dnl /* NXCOMP, NX protocol compression and NX extensions to this software */ -dnl /* are copyright of the aforementioned persons and companies. */ -dnl /* */ -dnl /* Redistribution and use of the present software is allowed according */ -dnl /* to terms specified in the file LICENSE.nxcomp which comes in the */ -dnl /* source distribution. */ -dnl /* */ -dnl /* All rights reserved. */ -dnl /* */ -dnl /* NOTE: This software has received contributions from various other */ -dnl /* contributors, only the core maintainers and supporters are listed as */ -dnl /* copyright holders. Please contact us, if you feel you should be listed */ -dnl /* as copyright holder, as well. */ -dnl /* */ -dnl /**************************************************************************/ - - -dnl Process this file with autoconf to produce a configure script. - -dnl Prolog - -AC_INIT(NX.h) -AC_PREREQ(2.13) - -pkgconfigdir=${libdir}/pkgconfig -AC_SUBST(pkgconfigdir) - -dnl Set our default compilation flags. - -if test "x$CXXFLAGS" = "x"; then - CXXFLAGS="-O3 -fno-rtti -fno-exceptions" -fi -if test "x$CFLAGS" = "x"; then - CFLAGS="$CFLAGS -O3" -fi - -dnl Reset default linking directives. - -LIBSTATIC="" -LIBSHARED="" - -dnl Prefer headers and libraries from nx-X11, if present. - -if test -d "../nx-X11/include" ; then - CXXFLAGS="$CXXFLAGS -I../nx-X11/exports/include" - CFLAGS="$CFLAGS -I../nx-X11/exports/include" - LIBS="$LIBS -L../nx-X11/exports/lib" -fi - -dnl Check whether --with-ipaq was given. - -if test "${with_ipaq}" = yes; then - echo -e "enabling IPAQ configuration" - CXX="arm-linux-c++" - CC="arm-linux-gcc" - unset ac_cv_prog_armcxx - unset ac_cv_prog_armcc - unset ac_cv_prog_CXXCPP - AC_CHECK_PROG([armcxx],["$CXX"],[yes],[no],[$PATH]) - AC_CHECK_PROG([armcc],["$CC"],[yes],[no],[$PATH]) - if test $armcxx = "yes" && test $armcc = "yes" ; then - ac_cv_prog_CXX="$CXX" - ac_cv_prog_CC="$CC" - else - AC_MSG_ERROR(Installation or configuration problem. Cannot find compiler for arm-linux.) - fi -else - unset ac_cv_prog_CXX - unset ac_cv_prog_CC - unset ac_cv_prog_CXXCPP -fi - -dnl Check for programs. - -AC_PROG_CXX -AC_PROG_CC -AC_LANG_CPLUSPLUS - -dnl Check whether option -Wno-deprecated -dnl is needed by GCC compiler. - -AC_MSG_CHECKING([whether compiler needs -Wno-deprecated]) -gcc_version=`${CC} --version | grep 'gcc (GCC) [[3-4]].' | head -n 1` -case "${gcc_version}" in - gcc*) - AC_MSG_RESULT([yes]) - CXXFLAGS="$CXXFLAGS -Wno-deprecated" - ;; - - *) - AC_MSG_RESULT([no]) - ;; -esac - -AC_MSG_CHECKING([whether compiler accepts -Wmissing-declarations]) -gcc_version=`${CC} --version | grep 'gcc (GCC) [[3-4]].' | head -n 1` -case "${gcc_version}" in - gcc*) - AC_MSG_RESULT([no]) - ;; - - *) - AC_MSG_RESULT([yes]) - CXXFLAGS="$CXXFLAGS -Wmissing-declarations" - ;; -esac - -dnl Check for BSD compatible install. - -AC_PROG_INSTALL - -dnl Check for extra header files. - -AC_PATH_XTRA - -dnl Custom addition. - -ac_help="$ac_help - --with-symbols add the -g flag to produce the debug symbols - --with-use-malloc add the __USE_MALLOC flag to avoid the STL allocators - --with-info define INFO at compile time to get basic log output - --with-valgrind clean up allocated buffers to avoid valgrind warnings - --with-version use this version for produced libraries - - --with-static-png enable static linking of PNG library - --with-static-jpeg enable static linking of JPEG library - --with-static-z enable static linking of Z library" - -dnl Check to see if we're running under Cygwin32. - -AC_DEFUN(nxconf_CYGWIN32, -[AC_CACHE_CHECK(for Cygwin32 environment, nxconf_cv_cygwin32, -[AC_TRY_COMPILE(,[return __CYGWIN32__;], -nxconf_cv_cygwin32=yes, nxconf_cv_cygwin32=no) -rm -f conftest*]) -CYGWIN32= -test "$nxconf_cv_cygwin32" = yes && CYGWIN32=yes]) -nxconf_CYGWIN32 - -dnl Check whether we're building on a AMD64. - -AC_DEFUN(nxconf_AMD64, -[AC_CACHE_CHECK(for Amd64 environment, nxconf_cv_amd64, -[AC_TRY_COMPILE(,[return (__amd64__ || __x86_64__);], -nxconf_cv_amd64=yes, nxconf_cv_amd64=no) -rm -f conftest*]) -AMD64= -test "$nxconf_cv_amd64" = yes && AMD64=yes]) -nxconf_AMD64 - -dnl Check for Darwin environment. - -AC_DEFUN(nxconf_DARWIN, -[AC_CACHE_CHECK(for Darwin environment, nxconf_cv_darwin, -[AC_TRY_COMPILE(,[return __APPLE__;], -nxconf_cv_darwin=yes, nxconf_cv_darwin=no) -rm -f conftest*]) -DARWIN= -test "$nxconf_cv_darwin" = yes && DARWIN=yes]) -nxconf_DARWIN - -dnl Check to see if we're running under Solaris. - -AC_DEFUN(nxconf_SUN, -[AC_CACHE_CHECK(for Solaris environment, nxconf_cv_sun, -[AC_TRY_COMPILE(,[return __sun;], -nxconf_cv_sun=yes, nxconf_cv_sun=no) -rm -f conftest*]) -SUN= -test "$nxconf_cv_sun" = yes && SUN=yes]) -nxconf_SUN - -dnl Check to see if we're running under FreeBSD. - -AC_DEFUN(nxconf_FreeBSD, -[AC_CACHE_CHECK(for FreeBSD environment, nxconf_cv_freebsd, -[AC_TRY_COMPILE(,[return __FreeBSD__;], -nxconf_cv_freebsd=yes, nxconf_cv_freebsd=no) -rm -f conftest*]) -FreeBSD= -test "$nxconf_cv_freebsd" = yes && FreeBSD=yes]) -nxconf_FreeBSD - -dnl Build PIC libraries. - -if test "$CYGWIN32" != yes -a "$DARWIN" != yes; then - CXXFLAGS="$CXXFLAGS -fPIC" - CFLAGS="$CFLAGS -fPIC" -fi - -dnl Solaris requires the socket and gcc_s libs explicitly linked. -dnl Note also that headers from default /usr/openwin/include/X11 -dnl cause a warning due to pragma in Xmd.h. - -if test "$SUN" = yes; then - LIBS="$LIBS -L/usr/sfw/lib -lsocket " - CXXFLAGS="$CXXFLAGS -I/usr/sfw/include" - CFLAGS="$CFLAGS -I/usr/sfw/include" -fi - -dnl On FreeBSD search libraries and includes under /usr/local. - -if test "$FreeBSD" = yes; then - LIBS="$LIBS -L/usr/local/lib" - CXXFLAGS="$CXXFLAGS -I/usr/local/include" - CFLAGS="$CFLAGS -I/usr/local/include" -fi - -dnl Under Darwin we don't have support for -soname option and -dnl we need the -dynamiclib flag. Under Solaris, instead, we need -dnl the options -G -h. - -if test "$DARWIN" = yes; then - LDFLAGS="$LDFLAGS -dynamiclib" -elif test "$SUN" = yes; then - LDFLAGS="$LDFLAGS -G -h \$(LIBLOAD)" -else - LDFLAGS="$LDFLAGS -Wl,-soname,\$(LIBLOAD)" -fi - -dnl Check to see if in_addr_t is defined. -dnl Could use a specific configure test. - -AC_DEFUN(nxconf_INADDRT, -[AC_CACHE_CHECK(for in_addr_t, nxconf_cv_inaddrt, -[AC_TRY_COMPILE([#include ],[in_addr_t t; t = 1; return t;], -nxconf_cv_inaddrt=yes, nxconf_cv_inaddrt=no) -rm -f conftest*]) -INADDRT= -test "$nxconf_cv_inaddrt" = yes && INADDRT=yes]) -nxconf_INADDRT - -dnl If in_addr_t is not defined use unsigned int. - -if test "$INADDRT" != yes ; then - echo -e "using unsigned int for type in_addr_t" - CXXFLAGS="$CXXFLAGS -DIN_ADDR_T=unsigned" - CFLAGS="$CFLAGS -DIN_ADDR_T=unsigned" -else - CXXFLAGS="$CXXFLAGS -DIN_ADDR_T=in_addr_t" - CFLAGS="$CFLAGS -DIN_ADDR_T=in_addr_t" -fi - -dnl Check whether --with-version was given. - -AC_SUBST(LIBVERSION) -AC_SUBST(VERSION) -if test "${with_version}" = yes; then - VERSION=${ac_option} -else - VERSION=`cat VERSION` -fi -echo -e "compiling version ${VERSION}" - -LIBVERSION=`echo ${VERSION} | cut -d '.' -f 1` - -CXXFLAGS="$CXXFLAGS -DVERSION=\\\"${VERSION}\\\"" -CFLAGS="$CFLAGS -DVERSION=\\\"${VERSION}\\\"" - -dnl Check whether --with-static-png was given and -dnl add -lpng or libpng.a to linking. - -if test "${with_static_png}" = yes; then - echo -e "enabling static linking of PNG library" - if test "$SUN" = yes && test -f "/usr/sfw/lib/libpng.a"; then - LIBSTATIC="$LIBSTATIC /usr/sfw/lib/libpng.a" - else - if test -f "/usr/lib/libpng.a" ; then - LIBSTATIC="$LIBSTATIC /usr/lib/libpng.a" - else - if test -f "/usr/local/lib/libpng.a" ; then - echo -e "assuming libpng.a in /usr/local/lib" - LIBSTATIC="$LIBSTATIC /usr/local/lib/libpng.a" - else - echo -e "Warning: assuming libpng.a in the local path" - LIBSTATIC="$LIBSTATIC libpng.a" - fi - fi - fi -else - echo -e "enabling dynamic linking of PNG library" - LIBSHARED="$LIBSHARED -lpng" -fi - -dnl Check whether --with-static-jpeg was given and -dnl add -ljpeg or libjpeg.a to linking. - -if test "${with_static_jpeg}" = yes; then - echo -e "enabling static linking of JPEG library" - if test "$SUN" = yes && test -f "/usr/sfw/lib/libjpeg.a"; then - LIBSTATIC="$LIBSTATIC /usr/sfw/lib/libjpeg.a" - else - if test -f "/usr/lib/libjpeg.a" ; then - LIBSTATIC="$LIBSTATIC /usr/lib/libjpeg.a" - else - if test -f "/usr/local/lib/libjpeg.a" ; then - echo -e "assuming libjpeg.a in /usr/local/lib" - LIBSTATIC="$LIBSTATIC /usr/local/lib/libjpeg.a" - else - echo -e "Warning: assuming libjpeg.a in the local path" - LIBSTATIC="$LIBSTATIC libjpeg.a" - fi - fi - fi -else - echo -e "enabling dynamic linking of JPEG library" - LIBSHARED="$LIBSHARED -ljpeg" -fi - -dnl Check whether --with-static-z was given and -dnl add -lz or libz.a to linking. - -if test "${with_static_z}" = yes; then - echo -e "enabling static linking of Z library" - if test "$SUN" = yes && test -f "/usr/sfw/lib/libz.a"; then - LIBSTATIC="$LIBSTATIC /usr/sfw/lib/libz.a" - else - if test -f "/usr/lib/libz.a" ; then - LIBSTATIC="$LIBSTATIC /usr/lib/libz.a" - else - if test -f "/usr/local/lib/libz.a" ; then - echo -e "assuming libz.a in /usr/local/lib" - LIBSTATIC="$LIBSTATIC /usr/local/lib/libz.a" - else - echo -e "Warning: assuming libz.a in the local path" - LIBSTATIC="$LIBSTATIC libz.a" - fi - fi - fi -else - echo -e "enabling dynamic linking of Z library" - LIBSHARED="$LIBSHARED -lz" -fi - -dnl Finally compose the LIB variable. - -if test "$DARWIN" = yes ; then - LIBS="$LIBS $LIBSTATIC $LIBSHARED" -elif test "$SUN" = yes ; then - LIBS="$LIBS $LIBSTATIC $LIBSHARED" -else - LIBS="$LIBS $LIBSTATIC -shared $LIBSHARED" -fi - -dnl Check whether --with-symbols or --without-symbols was -dnl given and set the required optimization level. - -if test "${with_symbols}" = yes; then - echo -e "enabling production of debug symbols" - CXXFLAGS="-g $CXXFLAGS" - CFLAGS="-g $CFLAGS" -else - echo -e "disabling production of debug symbols" -fi - -dnl Check whether --with-use-malloc or --without-use-malloc -dnl was given. - -if test "${with_use_malloc}" = yes; then - echo -e "disabling use of the STL allocators" - CXXFLAGS="$CXXFLAGS -D__USE_MALLOC" -else - echo -e "enabling use of the STL allocators" -fi - -dnl Check whether --with-info or --without-info was given. - -if test "${with_info}" = yes; then - echo -e "enabling info output in the log file" - CXXFLAGS="$CXXFLAGS -DINFO" - CFLAGS="$CFLAGS -DINFO" -else - echo -e "disabling info output in the log file" -fi - -dnl Check whether --with-valgrind or --without-valgrind was given. - -if test "${with_valgrind}" = yes; then - echo -e "enabling valgrind memory checker workarounds" - CXXFLAGS="$CXXFLAGS -DVALGRIND" - CFLAGS="$CFLAGS -DVALGRIND" -else - echo -e "disabling valgrind memory checker workarounds" -fi - -dnl Find makedepend somewhere. - -AC_SUBST(MAKEDEPEND) -MAKEDEPEND="$(which makedepend)" - -dnl Determine what to build based on the platform. -dnl Override the LIBS settings on Cygwin32 so that -dnl we always link with the exact set of libraries. - -AC_SUBST(ALL) - -if test "$CYGWIN32" = yes; then - ALL="\$(LIBCYGARCHIVE) \$(LIBCYGSHARED) \$(LIBARCHIVE)" - LIBS="-lstdc++ -lpng -ljpeg -lz" -else - ALL="\$(LIBFULL) \$(LIBLOAD) \$(LIBSHARED) \$(LIBARCHIVE)" -fi - -AC_OUTPUT(Makefile nxcomp.pc) diff --git a/nxcomp/include/MD5.h b/nxcomp/include/MD5.h new file mode 100644 index 000000000..698c995d8 --- /dev/null +++ b/nxcomp/include/MD5.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/nxcomp/include/NX.h b/nxcomp/include/NX.h new file mode 100644 index 000000000..7ec79b4b1 --- /dev/null +++ b/nxcomp/include/NX.h @@ -0,0 +1,471 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef NX_H +#define NX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include +#include +#include + +#define NX_FD_ANY -1 + +#define NX_MODE_ANY -1 +#define NX_MODE_CLIENT 1 +#define NX_MODE_SERVER 2 + +#define NX_DISPLAY_ANY NULL + +#define NX_SIGNAL_ANY -1 +#define NX_SIGNAL_ENABLE 1 +#define NX_SIGNAL_DISABLE 2 +#define NX_SIGNAL_RAISE 3 +#define NX_SIGNAL_FORWARD 4 + +#define NX_POLICY_IMMEDIATE 1 +#define NX_POLICY_DEFERRED 2 + +#define NX_ALERT_REMOTE 0 +#define NX_ALERT_LOCAL 1 + +#define NX_HANDLER_FLUSH 0 +#define NX_HANDLER_STATISTICS 1 + +#define NX_STATISTICS_PARTIAL 0 +#define NX_STATISTICS_TOTAL 1 + +#define NX_CHANNEL_X11 0 +#define NX_CHANNEL_CUPS 1 +#define NX_CHANNEL_SMB 2 +#define NX_CHANNEL_MEDIA 3 +#define NX_CHANNEL_HTTP 4 +#define NX_CHANNEL_FONT 5 +#define NX_CHANNEL_SLAVE 6 + +#define NX_FILE_SESSION 0 +#define NX_FILE_ERRORS 1 +#define NX_FILE_OPTIONS 2 +#define NX_FILE_STATS 3 + +/* + * The following are the new interfaces to the NX transport. The + * NX proxy software is now intended to be run as a library of a + * higher level communication manager (nxssh, nxhttp, nxrtp, etc, + * not only nxproxy). This is a work-in-progress, so expect these + * interfaces to change in future. At the present moment, as an + * example, there is no provision for creating and managing mul- + * tiple proxy connections. + */ + +/* + * Attach a NX transport to the provided descriptor. This should be + * done after having created a pair of connected sockets. + */ + +extern int NXTransCreate(int fd, int mode, const char *options); + +/* + * Tell the proxy to use the second descriptor as its own end of + * the internal connection to the NX agent. The NX agent will use + * the first descriptor. Setting an agent connection will have the + * effect of disabling further X client connections and, if it is + * possible, will trigger the use of the memory-to-memory transport. + */ + +extern int NXTransAgent(int fd[2]); + +/* + * Prepare the file sets and the timeout for a later execution of + * the select(). The masks and the timeout must persist across all + * the calls, so if you don't need any of the values, it is requi- + * red that you create empty masks and a default timeout. To save + * a check at each run, all the functions below assume that valid + * pointers are passed. + */ + +extern int NXTransPrepare(int *maxfds, fd_set *readfds, + fd_set *writefds, struct timeval *timeout); + +/* + * Call select() to find out the descriptors in the sets having + * pending data. + */ + +extern int NXTransSelect(int *result, int *error, int *maxfds, fd_set *readfds, + fd_set *writefds, struct timeval *timeout); + +/* + * Perform the required I/O on all the NX descriptors having pen- + * ding data. This can include reading and writing to the NX chan- + * nels, encoding and decoding the proxy data or managing any of + * the other NX resources. + */ + +extern int NXTransExecute(int *result, int *error, int *maxfds, fd_set *readfds, + fd_set *writefds, struct timeval *timeout); + +/* + * Run an empty loop, giving to the NX transport a chance to check + * its descriptors. + */ + +extern int NXTransContinue(struct timeval *timeout); + +/* + * Perform I/O on the given descriptors. If memory-to-memory trans- + * port has been activated and the descriptor is recognized as a + * valid agent connection, then the functions will read and write + * the data directly to the proxy buffer, otherwise the correspond- + * ing network operation will be performed. + */ + +extern int NXTransRead(int fd, char *data, int size); +extern int NXTransWrite(int fd, char *data, int size); +extern int NXTransReadable(int fd, int *readable); + +extern int NXTransReadVector(int fd, struct iovec *iovdata, int iovsize); +extern int NXTransWriteVector(int fd, struct iovec *iovdata, int iovsize); + +extern int NXTransClose(int fd); + +/* + * Return true if the NX transport is running. The fd parameter can + * be either the local descriptor attached to the NX transport or + * NX_FD_ANY. + */ + +extern int NXTransRunning(int fd); + +/* + * Close down the NX transport and free all the allocated resources. + * The fd parameter can be either the local descriptor or NX_FD_ANY. + * This must be explicitly called by the agent before the proxy can + * start the tear down procedure. + */ + +extern int NXTransDestroy(int fd); + +/* + * Tell to the proxy how to handle the standard POSIX signals. For + * example, given the SIGINT signal, the caller can specify any of + * the following actions: + * + * NX_SIGNAL_ENABLE: A signal handler will have to be installed by + * the library, so that it can be intercepted by + * the proxy. + * + * NX_SIGNAL_DISABLE: The signal will be handled by the caller and, + * eventually, forwarded to the proxy by calling + * NXTransSignal() explicitly. + * + * NX_SIGNAL_RAISE: The signal must be handled now, as if it had + * been delivered by the operating system. This + * function can be called by the agent with the + * purpose of propagating a signal to the proxy. + * + * NX_SIGNAL_FORWARD: A signal handler will have to be installed by + * the library but the library will have to call + * the original signal handler when the signal + * is received. + * + * As a rule of thumb, agents should let the proxy handle SIGUSR1 + * and SIGUSR2, used for producing the NX protocol statistics, and + * SIGHUP, used for disconnecting the NX transport. + * + * The following signals are blocked by default upon creation of the + * NX transport: + * + * SIGCHLD These signals should be always put under the control + * SIGUSR1 of the proxy. If agents are intercepting them, agents + * SIGUSR2 should later call NXTransSignal(..., NX_SIGNAL_RAISE) + * SIGHUP to forward the signal to the proxy. As an alternative + * they can specify a NX_SIGNAL_FORWARD action, so they, + * in turn, can be notified about the signal. This can + * be especially useful for SIGCHLD. + * + * SIGINT These signals should be intercepted by agents. Agents + * SIGTERM should ensure that NXTransDestroy() is called before + * exiting, to give the proxy a chance to shut down the + * NX transport. + * + * SIGPIPE This signal is blocked by the proxy, but not used to + * implement any functionality. It can be handled by the + * NX agent without affecting the proxy. + * + * SIGALRM This is now used by the proxy and agents should not + * redefine it. Agents can use the signal to implement + * their own timers but should not interleave calls to + * the NX transport and should restore the old handler + * when the timeout is raised. + * + * SIGVTALRM These signals are not used but may be used in future + * SIGWINCH versions of the library. + * SIGIO + * SIGTSTP + * SIGTTIN + * SIGTTOU + * + * By calling NXTransSignal(..., NX_SIGNAL_DISABLE) nxcomp will res- + * tore the signal handler that was saved at the time the proxy hand- + * ler was installed. This means that you should call the function + * just after the XOpenDisplay() or any other function used to init- + * ialize the NX transport. + */ + +extern int NXTransSignal(int signal, int action); + +/* + * Return a value between 0 and 9 indicating the congestion level + * based on the tokens still available. A value of 9 means that + * the link is congested and no further data can be sent. + */ + +extern int NXTransCongestion(int fd); + +/* + * Let the application to be notified by the proxy when an event oc- + * curs. The parameter, as set at the time the handler is installed, + * is passed each time to the callback function. The parameter is + * presumably the display pointer, given that at the present moment + * the NX transport doesn't have access to the display structure and + * so wouldn't be able to determine the display to pass to the call- + * back function. + * + * NX_HANDLER_FLUSH: The handler function is called when some + * more data has been written to the proxy + * link. + * + * The data is the number of bytes written. + * + * NX_HANDLER_STATISTICS: This handler is called to let the agent + * include arbitrary data in the transport + * statistics. The parameter, in this case, + * is a pointer to a pointer to a null term- + * inated string. The pointer is set at the + * time the handler is registered. The point- + * ed string will have to be filled by the + * agent with its statistics data. + * + * The data can be NX_STATISTICS_PARTIAL or NX_STATISTICS_TOTAL. The + * agent can refer to the value by using the NXStatisticsPartial and + * NXStatisticsTotal constants defined in NXvars.h. + * + * Note that these interfaces are used by Xlib and nxcompext. Agents + * should never call these interfaces directly, but use the nxcompext + * wrapper. + */ + +extern int NXTransHandler(int fd, int type, void (*handler)(void *parameter, + int reason), void *parameter); + +/* + * Set the policy to be used by the NX transport to write data to the + * proxy link: + * + * NX_POLICY_IMMEDIATE: When set to immediate, the proxy will try to + * write the data just after having encoded it. + * + * NX_POLICY_DEFERRED: When policy is set to deferred, data will be + * accumulated in a buffer and written to the + * remote proxy when NXTransFlush() is called by + * the agent. + */ + +extern int NXTransPolicy(int fd, int type); + +/* + * Query the number of bytes that have been accumulated for a deferred + * flush. + */ + +extern int NXTransFlushable(int fd); + +/* + * Tell to the NX transport to write all the accumulated data to the + * remote proxy. + */ + +extern int NXTransFlush(int fd); + +/* + * Create a new channel of the given type. It returns 1 on success, + * 0 if the NX transport is not running, or -1 in the case of error. + * On success, the descriptor provided by the caller can be later + * used for the subsequent I/O. The type parameter not only tells to + * the proxy the remote port where the channel has to be connected, + * but also gives a hint about the type of data that will be carried + * by the channel, so that the proxy can try to optimize the traffic + * on the proxy link. + * + * NX_CHANNEL_X: The channel will carry X traffic and it + * will be connected to the remote X display. + * + * NX_CHANNEL_CUPS: The channel will carry CUPS/IPP protocol. + * + * NX_CHANNEL_SMB: The channel will carry SMB/CIFS protocol. + * + * NX_CHANNEL_MEDIA: The channel will transport audio or other + * multimedia data. + * + * NX_CHANNEL_HTTP: The channel will carry HTTP protocol. + * + * NX_CHANNEL_FONT: The channel will forward a X font server + * connection. + * + * Only a proxy running at the NX server/X client side will be able + * to create a X, CUPS, SMB, MEDIA and HTTP channel. A proxy running + * at the NX client/X server side can create font server connections. + * The channel creation will also fail if the remote end has not been + * set up to forward the connection. + * + * To create a new channel the agent will have to set up a socketpair + * and pass to the proxy one of the socket descriptors. + * + * Example: + * + * #include + * #include + * + * int fds[2]; + * + * if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) + * { + * ... + * } + * else + * { + * // + * // Use fds[0] locally and let the + * // proxy use fds[1]. + * // + * + * if (NXTransChannel(NX_FD_ANY, fds[1], NX_CHANNEL_X) <= 0) + * { + * ... + * } + * + * // + * // The agent can now use fds[0] in + * // read(), write() and select() + * // system calls. + * // + * + * ... + * } + * + * Note that all the I/O on the descriptor should be non-blocking, to + * give a chance to the NX transport to run in the background and handle + * the data that will be fed to the agent's side of the socketpair. This + * will happen automatically, as long as the agent uses the XSelect() + * version of the select() function (as it is normal whenever performing + * Xlib I/O). In all the other cases, like presumably in the agent's main + * loop, the agent will have to loop through NXTransPrepare(), NXTrans- + * Select() and NXTransExecute() functions explicitly, adding to the sets + * the descriptors that are awaited by the agent. Please check the imple- + * mentation of _XSelect() in nx-X11/lib/X11/XlibInt.c for an example. + */ + +extern int NXTransChannel(int fd, int channelfd, int type); + +/* + * Return the name of the files used by the proxy for the current session. + * + * The type parameter can be: + * + * NX_FILE_SESSION: Usually the file 'session' in the user's session + * directory. + * + * NX_FILE_ERRORS: The file used for the diagnostic output. Usually + * the file 'errors' in the session directory. + * + * NX_FILE_OPTIONS: The file containing the NX options, if any. + * + * NX_FILE_STATS: The file used for the statistics output. + * + * The returned string is allocated in static memory. The caller should + * copy the string upon returning from the function, without freeing the + * pointer. + */ + +extern const char *NXTransFile(int type); + +/* + * Return the time in milliseconds elapsed since the last call to this + * same function. + */ + +extern long NXTransTime(void); + +/* + * Other interfaces to the internal transport functions. + */ + +extern int NXTransProxy(int fd, int mode, const char *display); + +extern int NXTransClient(const char *display); + +extern int NXTransDialog(const char *caption, const char *message, + const char *window, const char *type, int local, + const char *display); + +extern int NXTransAlert(int code, int local); + +extern int NXTransWatchdog(int timeout); + +extern int NXTransKeeper(int caches, int images, const char *root); + +extern void NXTransExit(int code) __attribute__((noreturn)); + +extern int NXTransParseCommandLine(int argc, const char **argv); +extern int NXTransParseEnvironment(const char *env, int force); + +extern void NXTransCleanup(void) __attribute__((noreturn)); + +/* + * Cleans up the global and local state + * (the same way as NXTransCleanup does) + * but does not exit the process + * Needed for IOS platform + */ +extern void NXTransCleanupForReconnect(void); + +extern const char* NXVersion(void); +extern int NXMajorVersion(void); +extern int NXMinorVersion(void); +extern int NXPatchVersion(void); +extern int NXMaintenancePatchVersion(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NX_H */ diff --git a/nxcomp/include/NXalert.h b/nxcomp/include/NXalert.h new file mode 100644 index 000000000..dca2f44ca --- /dev/null +++ b/nxcomp/include/NXalert.h @@ -0,0 +1,276 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef NXalert_H +#define NXalert_H + +#define ALERT_CAPTION_PREFIX "NX - " + +#define INTERNAL_ERROR_ALERT 1 +#define INTERNAL_ERROR_ALERT_TYPE "error" +#define INTERNAL_ERROR_ALERT_STRING \ +"\ +An unrecoverable internal error was detected.\n\ +Press OK to terminate the current session.\n\ +" + +#define CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT 2 +#define CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_TYPE "yesno" +#define CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_STRING \ +"\ +One of the applications currently in use is not responding.\n\ +Do you want to terminate the current session?\n\ +" + +#define CLOSE_DEAD_X_CONNECTION_SERVER_ALERT 3 +#define CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_TYPE "yesno" +#define CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_STRING \ +"\ +One of the applications did not behave correctly and caused\n\ +the X server to stop responding in a timely fashion. Do you\n\ +want to terminate the current session?\n\ +" + +#define CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT 4 +#define CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT_TYPE NULL +#define CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT_STRING NULL + +#define CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT 5 +#define CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE "yesno" +#define CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING \ +"\ +No response received from the remote server.\n\ +Do you want to terminate the current session?\n\ +" + +#define RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT 6 +#define RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT_TYPE NULL +#define RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT_STRING NULL + +#define RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT 7 +#define RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE "yesno" +#define RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING \ +"\ +Connection with remote server was shut down. NX will try\n\ +to establish a new server connection. Session could have\n\ +been left in a unusable state. Do you want to terminate\n\ +the session?\n\ +" + +#define CLOSE_UNRESPONSIVE_X_SERVER_ALERT 8 +#define CLOSE_UNRESPONSIVE_X_SERVER_ALERT_TYPE "panic" +#define CLOSE_UNRESPONSIVE_X_SERVER_ALERT_STRING \ +"\ +You pressed the key sequence CTRL+ALT+SHIFT+ESC.\n\ +This is probably because your X server has become\n\ +unresponsive. Session will be terminated in 30\n\ +seconds unless you abort the procedure by pressing\n\ +the Cancel button.\n\ +" + +#define WRONG_PROXY_VERSION_ALERT 9 +#define WRONG_PROXY_VERSION_ALERT_TYPE "ok" +#define WRONG_PROXY_VERSION_ALERT_STRING \ +"\ +Local NX libraries version " VERSION " do not match the NX\n\ +version of the remote server. Please check the error\n\ +log on the server to find out which client version you\n\ +need to install to be able to access this server.\n\ +" + +#define FAILED_PROXY_CONNECTION_CLIENT_ALERT 10 +#define FAILED_PROXY_CONNECTION_CLIENT_ALERT_TYPE NULL +#define FAILED_PROXY_CONNECTION_CLIENT_ALERT_STRING NULL + +#define FAILED_PROXY_CONNECTION_SERVER_ALERT 11 +#define FAILED_PROXY_CONNECTION_SERVER_ALERT_TYPE "yesno" +#define FAILED_PROXY_CONNECTION_SERVER_ALERT_STRING \ +"\ +Could not yet establish the connection to the remote\n\ +proxy. Do you want to terminate the current session?\n\ +" + +#define MISSING_PROXY_CACHE_ALERT 12 +#define MISSING_PROXY_CACHE_ALERT_TYPE "ok" +#define MISSING_PROXY_CACHE_ALERT_STRING \ +"\ +NX was unable to negotiate a cache for this session.\n\ +This may happen if this is the first time you run a\n\ +session on this server or if cache was corrupted or\n\ +produced by an incompatible NX version.\n\ +" + +#define ABORT_PROXY_CONNECTION_ALERT 13 +#define ABORT_PROXY_CONNECTION_ALERT_TYPE "ok" +#define ABORT_PROXY_CONNECTION_ALERT_STRING \ +"\ +The connection with the remote server was shut down.\n\ +Please check the state of your network connection.\n\ +" + +/* + * The one below is a special alert, used to close + * a previous alert that is running on the given + * side. This can be used to get rid of a message + * that has ceased to hold true. + */ + +#define DISPLACE_MESSAGE_ALERT 14 +#define DISPLACE_MESSAGE_ALERT_TYPE NULL +#define DISPLACE_MESSAGE_ALERT_STRING NULL + +/* + * These are the other alert messages that were + * added in the 1.5.0 release. The first is never + * shown and is intended just for testing. + */ + +#define GREETING_MESSAGE_ALERT 15 +#define GREETING_MESSAGE_ALERT_TYPE "ok" +#define GREETING_MESSAGE_ALERT_STRING \ +"\ +Welcome to NX from the NoMachine team. We really\n\ +hope you will enjoy this wonderful software as much\n\ +as we had fun making it ;-).\n\ +" + +/* + * These alerts are intended to notify the user + * of the reason why the agent failed to resume + * the session. + */ + +#define START_RESUME_SESSION_ALERT 16 +#define START_RESUME_SESSION_ALERT_TYPE "ok" +#define START_RESUME_SESSION_ALERT_STRING \ +"\ +You appear to run your NX session across a slow network\n\ +connection. Resuming the session may require some time.\n\ +Please wait.\ +" + +#define FAILED_RESUME_DISPLAY_ALERT 17 +#define FAILED_RESUME_DISPLAY_ALERT_TYPE "error" +#define FAILED_RESUME_DISPLAY_ALERT_STRING \ +"\ +Failed to open the display. Can't resume the NX\n\ +session on this display.\n\ +" + +#define FAILED_RESUME_DISPLAY_BROKEN_ALERT 18 +#define FAILED_RESUME_DISPLAY_BROKEN_TYPE "error" +#define FAILED_RESUME_DISPLAY_BROKEN_STRING \ +"\ +The display connection was broken while trying to\n\ +resume the session. Please, check your network\n\ +connection and try again.\n\ +" + +#define FAILED_RESUME_VISUALS_ALERT 19 +#define FAILED_RESUME_VISUALS_ALERT_TYPE "error" +#define FAILED_RESUME_VISUALS_ALERT_STRING \ +"\ +Failed to restore all the required visuals.\n\ +Can't resume the NX session on this display.\n\ +" + +#define FAILED_RESUME_COLORMAPS_ALERT 20 +#define FAILED_RESUME_COLORMAPS_ALERT_TYPE "error" +#define FAILED_RESUME_COLORMAPS_ALERT_STRING \ +"\ +The number of available colormaps is different\n\ +on the new display. Can't resume the NX session\n\ +on this display.\n\ +" + +#define FAILED_RESUME_PIXMAPS_ALERT 21 +#define FAILED_RESUME_PIXMAPS_ALERT_TYPE "error" +#define FAILED_RESUME_PIXMAPS_ALERT_STRING \ +"\ +Failed to restore all the required pixmap formats.\n\ +Can't resume the NX session on this display.\n\ +" + +#define FAILED_RESUME_DEPTHS_ALERT 22 +#define FAILED_RESUME_DEPTHS_ALERT_TYPE "error" +#define FAILED_RESUME_DEPTHS_ALERT_STRING \ +"\ +Failed to restore all the required screen depths.\n\ +Can't resume the NX session on this display.\n\ +" + +#define FAILED_RESUME_RENDER_ALERT 23 +#define FAILED_RESUME_RENDER_ALERT_TYPE "error" +#define FAILED_RESUME_RENDER_ALERT_STRING \ +"\ +The render extension is missing or an incompatible\n\ +version was detected on your X server. Can't resume\n\ +the NX session on this display.\n\ +" + +#define FAILED_RESUME_FONTS_ALERT 24 +#define FAILED_RESUME_FONTS_ALERT_TYPE "error" +#define FAILED_RESUME_FONTS_ALERT_STRING \ +"\ +One or more of the fonts that are in use by the\n\ +session are missing. Can't resume the NX session\n\ +on this display.\n\ +" + +#define ABORT_PROXY_NEGOTIATION_ALERT 62 +#define ABORT_PROXY_NEGOTIATION_ALERT_TYPE "ok" +#define ABORT_PROXY_NEGOTIATION_ALERT_STRING \ +"\ +The remote proxy closed the connection while negotiating\n\ +the session. This may be due to the wrong authentication\n\ +credentials passed to the server.\n\ +" + +#define ABORT_PROXY_SHUTDOWN_ALERT 64 +#define ABORT_PROXY_SHUTDOWN_ALERT_TYPE "ok" +#define ABORT_PROXY_SHUTDOWN_ALERT_STRING \ +"\ +No response received from the remote proxy while\n\ +waiting for the session shutdown.\n\ +" + +#define FAILED_XDMCP_CONNECTION_ALERT 65 +#define FAILED_XDMCP_CONNECTION_ALERT_TYPE "ok" +#define FAILED_XDMCP_CONNECTION_ALERT_STRING \ +"\ +The XDM host that was contacted by the NX server doesn't\n\ +seem to be able to start the session. Please check your\n\ +server configuration.\n\ +" + +/* + * Used to handle the backward compatibility. + * Update the numbers if you add a new alert. + */ + +#define LAST_PROTO_STEP_6_ALERT 63 +#define LAST_PROTO_STEP_7_ALERT 65 + +#endif /* NXalert_H */ diff --git a/nxcomp/include/NXpack.h b/nxcomp/include/NXpack.h new file mode 100644 index 000000000..3eade6855 --- /dev/null +++ b/nxcomp/include/NXpack.h @@ -0,0 +1,141 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef NXpack_H +#define NXpack_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MASK_METHOD_LIMIT 10 + +#define NO_MASK 0 + +#define MASK_8_COLORS 1 +#define MASK_64_COLORS 2 +#define MASK_256_COLORS 3 +#define MASK_512_COLORS 4 +#define MASK_4K_COLORS 5 +#define MASK_32K_COLORS 6 +#define MASK_64K_COLORS 7 +#define MASK_256K_COLORS 8 +#define MASK_2M_COLORS 9 +#define MASK_16M_COLORS 10 + +#define PACK_METHOD_LIMIT 128 + +#define NO_PACK 0 + +#define PACK_MASKED_8_COLORS 1 +#define PACK_MASKED_64_COLORS 2 +#define PACK_MASKED_256_COLORS 3 +#define PACK_MASKED_512_COLORS 4 +#define PACK_MASKED_4K_COLORS 5 +#define PACK_MASKED_32K_COLORS 6 +#define PACK_MASKED_64K_COLORS 7 +#define PACK_MASKED_256K_COLORS 8 +#define PACK_MASKED_2M_COLORS 9 +#define PACK_MASKED_16M_COLORS 10 + +#define PACK_RAW_8_BITS 3 +#define PACK_RAW_16_BITS 7 +#define PACK_RAW_24_BITS 10 + +#define PACK_COLORMAP_256_COLORS 11 + +#define PACK_JPEG_8_COLORS 26 +#define PACK_JPEG_64_COLORS 27 +#define PACK_JPEG_256_COLORS 28 +#define PACK_JPEG_512_COLORS 29 +#define PACK_JPEG_4K_COLORS 30 +#define PACK_JPEG_32K_COLORS 31 +#define PACK_JPEG_64K_COLORS 32 +#define PACK_JPEG_256K_COLORS 33 +#define PACK_JPEG_2M_COLORS 34 +#define PACK_JPEG_16M_COLORS 35 + +#define PACK_PNG_8_COLORS 37 +#define PACK_PNG_64_COLORS 38 +#define PACK_PNG_256_COLORS 39 +#define PACK_PNG_512_COLORS 40 +#define PACK_PNG_4K_COLORS 41 +#define PACK_PNG_32K_COLORS 42 +#define PACK_PNG_64K_COLORS 43 +#define PACK_PNG_256K_COLORS 44 +#define PACK_PNG_2M_COLORS 45 +#define PACK_PNG_16M_COLORS 46 + +#define PACK_RGB_16M_COLORS 63 +#define PACK_RLE_16M_COLORS 64 + +#define PACK_ALPHA 65 +#define PACK_COLORMAP 66 + +#define PACK_BITMAP_16M_COLORS 67 + +/* + * Not really pack methods. These values + * allow dynamic selection of the pack + * method by the agent. + */ + +#define PACK_NONE 0 +#define PACK_LOSSY 253 +#define PACK_LOSSLESS 254 +#define PACK_ADAPTIVE 255 + +/* + * Reduce the number of colors in the + * image by applying a mask. + */ + +typedef struct +{ + unsigned int color_mask; + unsigned int correction_mask; + unsigned int white_threshold; + unsigned int black_threshold; + +} ColorMask; + +extern const ColorMask Mask8TrueColor; +extern const ColorMask Mask64TrueColor; +extern const ColorMask Mask512TrueColor; +extern const ColorMask Mask4KTrueColor; +extern const ColorMask Mask32KTrueColor; +extern const ColorMask Mask256KTrueColor; +extern const ColorMask Mask2MTrueColor; +extern const ColorMask Mask16MTrueColor; + +const ColorMask *MethodColorMask(unsigned int method); + +int MethodBitsPerPixel(unsigned int method); + +#ifdef __cplusplus +} +#endif + +#endif /* NXpack_H */ diff --git a/nxcomp/include/NXproto.h b/nxcomp/include/NXproto.h new file mode 100644 index 000000000..7b988bdbf --- /dev/null +++ b/nxcomp/include/NXproto.h @@ -0,0 +1,447 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef NXproto_H +#define NXproto_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* + * Force the size to match the wire protocol. + */ + +#define Drawable CARD32 +#define GContext CARD32 + +#define sz_xNXGetControlParametersReq 4 +#define sz_xNXGetCleanupParametersReq 4 +#define sz_xNXGetImageParametersReq 4 +#define sz_xNXGetUnpackParametersReq 8 +#define sz_xNXGetShmemParametersReq 16 +#define sz_xNXGetFontParametersReq 4 +#define sz_xNXSetExposeParametersReq 8 +#define sz_xNXSetCacheParametersReq 8 +#define sz_xNXStartSplitReq 8 +#define sz_xNXEndSplitReq 4 +#define sz_xNXCommitSplitReq 12 +#define sz_xNXSetUnpackGeometryReq 24 +#define sz_xNXSetUnpackColormapReq 16 +#define sz_xNXSetUnpackAlphaReq 16 +#define sz_xNXPutPackedImageReq 40 +#define sz_xNXFreeUnpackReq 4 +#define sz_xNXFinishSplitReq 4 +#define sz_xNXAbortSplitReq 4 +#define sz_xNXFreeSplitReq 4 + +#define sz_xGetControlParametersReply 32 +#define sz_xGetCleanupParametersReply 32 +#define sz_xGetImageParametersReply 32 +#define sz_xGetUnpackParametersReply 32 +#define sz_xGetShmemParametersReply 32 + +#define LINK_TYPE_LIMIT 5 + +#define LINK_TYPE_NONE 0 +#define LINK_TYPE_MODEM 1 +#define LINK_TYPE_ISDN 2 +#define LINK_TYPE_ADSL 3 +#define LINK_TYPE_WAN 4 +#define LINK_TYPE_LAN 5 + +/* + * NX Replies. + */ + +/* + * The following reply has 4 new boolean + * fields in the last protocol version. + */ + +typedef struct _NXGetControlParametersReply { + BYTE type; /* Is X_Reply. */ + CARD8 linkType; + CARD16 sequenceNumber B16; + CARD32 length B32; /* Is 0. */ + CARD8 localMajor; + CARD8 localMinor; + CARD8 localPatch; + CARD8 remoteMajor; + CARD8 remoteMinor; + CARD8 remotePatch; + CARD16 splitTimeout B16; + CARD16 motionTimeout B16; + CARD8 splitMode; + CARD8 pad1; + CARD32 splitSize B32; + CARD8 packMethod; + CARD8 packQuality; + CARD8 dataLevel; + CARD8 streamLevel; + CARD8 deltaLevel; + CARD8 loadCache; + CARD8 saveCache; + CARD8 startupCache; +} xNXGetControlParametersReply; + +typedef struct _NXGetCleanupParametersReply { + BYTE type; /* Is X_Reply. */ + BYTE pad; + CARD16 sequenceNumber B16; + CARD32 length B32; /* Is 0. */ + BOOL cleanGet; + BOOL cleanAlloc; + BOOL cleanFlush; + BOOL cleanSend; + BOOL cleanImages; + BYTE pad1, pad2, pad3; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xNXGetCleanupParametersReply; + +typedef struct _NXGetImageParametersReply { + BYTE type; /* Is X_Reply. */ + BYTE pad; + CARD16 sequenceNumber B16; + CARD32 length B32; /* Is 0. */ + BOOL imageSplit; + BOOL imageMask; + BOOL imageFrame; + CARD8 imageMaskMethod; + CARD8 imageSplitMethod; + BYTE pad1, pad2, pad3; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xNXGetImageParametersReply; + +/* + * Data is made of PACK_METHOD_LIMIT values of + * type BOOL telling which unpack capabilities + * are implemented in proxy. + */ + +typedef struct _NXGetUnpackParametersReply { + BYTE type; /* Is X_Reply. */ + BYTE pad; + CARD16 sequenceNumber B16; + CARD32 length B32; /* Is PACK_METHOD_LIMIT / 4 from NXpack.h. */ + CARD8 entries; /* Is PACK_METHOD_LIMIT. */ + BYTE pad1, pad2, pad3; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; +} xNXGetUnpackParametersReply; + +typedef struct _NXGetShmemParametersReply { + BYTE type; /* Is X_Reply. */ + CARD8 stage; /* As in the corresponding request. */ + CARD16 sequenceNumber B16; + CARD32 length B32; /* Is 0. */ + BOOL clientEnabled; /* SHM on path agent to proxy. */ + BOOL serverEnabled; /* SHM on path proxy to X server. */ + BYTE pad1, pad2; /* Previous values can be checked */ + CARD32 clientSize B32; /* at end of stage 2. */ + CARD32 serverSize B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; +} xNXGetShmemParametersReply; + +typedef struct _NXGetFontParametersReply { + BYTE type; /* Is X_Reply. */ + BYTE pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; /* Is length of path string + 1 / 4. */ + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xNXGetFontParametersReply; + +/* + * NX Requests. + */ + +typedef struct _NXGetControlParametersReq { + CARD8 reqType; + BYTE pad; + CARD16 length B16; +} xNXGetControlParametersReq; + +typedef struct _NXGetCleanupParametersReq { + CARD8 reqType; + BYTE pad; + CARD16 length B16; +} xNXGetCleanupParametersReq; + +typedef struct _NXGetImageParametersReq { + CARD8 reqType; + BYTE pad; + CARD16 length B16; +} xNXGetImageParametersReq; + +typedef struct _NXGetUnpackParametersReq { + CARD8 reqType; + BYTE pad; + CARD16 length B16; + CARD8 entries; + BYTE pad1, pad2, pad3; +} xNXGetUnpackParametersReq; + +typedef struct _NXGetShmemParametersReq { + CARD8 reqType; + CARD8 stage; /* It is between 0 and 2. */ + CARD16 length B16; + BOOL enableClient; /* X client side support is */ + BOOL enableServer; /* not implemented yet. */ + BYTE pad1, pad2; + CARD32 clientSegment; /* XID identifying the shared */ + CARD32 serverSegment; /* memory segments. */ +} xNXGetShmemParametersReq; + +typedef struct _NXGetFontParametersReq { + CARD8 reqType; + CARD8 pad; + CARD16 length B16; +} xNXGetFontParametersReq; + +/* + * The available split modes. + */ + +#define NXSplitModeDefault 0 +#define NXSplitModeAsync 1 +#define NXSplitModeSync 2 + +typedef struct _NXStartSplitReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; + CARD8 mode; + BYTE pad1, pad2, pad3; +} xNXStartSplitReq; + +typedef struct _NXEndSplitReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; +} xNXEndSplitReq; + +typedef struct _NXCommitSplitReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; + CARD8 propagate; + CARD8 request; + BYTE pad1, pad2; + CARD32 position B32; +} xNXCommitSplitReq; + +typedef struct _NXFinishSplitReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; +} xNXFinishSplitReq; + +typedef struct _NXAbortSplitReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; +} xNXAbortSplitReq; + +typedef struct _NXFreeSplitReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; +} xNXFreeSplitReq; + +typedef struct _NXSetExposeParametersReq { + CARD8 reqType; + BYTE pad; + CARD16 length B16; + BOOL expose; + BOOL graphicsExpose; + BOOL noExpose; + BYTE pad1; +} xNXSetExposeParametersReq; + +typedef struct _NXSetCacheParametersReq { + CARD8 reqType; + BYTE pad; + CARD16 length B16; + BOOL enableCache; + BOOL enableSplit; + BOOL enableSave; + BOOL enableLoad; +} xNXSetCacheParametersReq; + +typedef struct _NXSetUnpackGeometryReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; + CARD8 depth1Bpp; + CARD8 depth4Bpp; + CARD8 depth8Bpp; + CARD8 depth16Bpp; + CARD8 depth24Bpp; + CARD8 depth32Bpp; + BYTE pad1, pad2; + CARD32 redMask B32; + CARD32 greenMask B32; + CARD32 blueMask B32; +} xNXSetUnpackGeometryReq; + +typedef struct _NXSetUnpackColormapReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; + CARD8 method; + BYTE pad1, pad2, pad3; + CARD32 srcLength B32; + CARD32 dstLength B32; +} xNXSetUnpackColormapReq; + +typedef struct _NXSetUnpackAlphaReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; + CARD8 method; + BYTE pad1, pad2, pad3; + CARD32 srcLength B32; + CARD32 dstLength B32; +} xNXSetUnpackAlphaReq; + +typedef struct _NXPutPackedImageReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; + Drawable drawable B32; + GContext gc B32; + CARD8 method; + CARD8 format; + CARD8 srcDepth; + CARD8 dstDepth; + CARD32 srcLength B32; + CARD32 dstLength B32; + INT16 srcX B16, srcY B16; + CARD16 srcWidth B16, srcHeight B16; + INT16 dstX B16, dstY B16; + CARD16 dstWidth B16, dstHeight B16; +} xNXPutPackedImageReq; + +typedef struct _NXFreeUnpackReq { + CARD8 reqType; + CARD8 resource; + CARD16 length B16; +} xNXFreeUnpackReq; + +/* + * The X_NXSplitData and X_NXSplitEvent opcodes + * are used internally and are ignored if coming + * from the agent. + */ + +#define X_NXInternalGenericData 0 +#define X_NXInternalGenericReply 1 +#define X_NXInternalGenericRequest 255 + +#define X_NXInternalShapeExtension 128 +#define X_NXInternalRenderExtension 129 + +#define X_NXFirstOpcode 230 +#define X_NXLastOpcode 252 + +#define X_NXGetControlParameters 230 +#define X_NXGetCleanupParameters 231 +#define X_NXGetImageParameters 232 +#define X_NXGetUnpackParameters 233 +#define X_NXStartSplit 234 +#define X_NXEndSplit 235 +#define X_NXSplitData 236 +#define X_NXCommitSplit 237 +#define X_NXSetExposeParameters 240 +#define X_NXSetUnpackGeometry 241 +#define X_NXSetUnpackColormap 242 +#define X_NXPutPackedImage 243 +#define X_NXSplitEvent 244 +#define X_NXGetShmemParameters 245 +#define X_NXSetUnpackAlpha 246 +#define X_NXFreeUnpack 247 +#define X_NXFinishSplit 248 +#define X_NXAbortSplit 249 +#define X_NXFreeSplit 250 +#define X_NXGetFontParameters 251 +#define X_NXSetCacheParameters 252 + +/* + * The following events are received by the agent + * in the form of a ClientMessage with the value + * 0 in fields atom and window. The format is + * always 32. Event specific data starts at byte + * offset 12. + * + * These events are sent by the NX transport to + * notify the agent about the result of a split + * operation. + */ + +#define NXNoSplitNotify 1 +#define NXStartSplitNotify 2 +#define NXCommitSplitNotify 3 +#define NXEndSplitNotify 4 +#define NXEmptySplitNotify 5 + +/* + * Notifications of collect events. These events + * don't come from the NX transport but are put + * back in client's event queue by NXlib. + */ + +#define NXCollectImageNotify 8 +#define NXCollectPropertyNotify 9 +#define NXCollectGrabPointerNotify 10 +#define NXCollectInputFocusNotify 11 + +#undef Drawable +#undef GContext + +#ifdef __cplusplus +} +#endif + +#endif /* NXproto_H */ diff --git a/nxcomp/include/NXvars.h b/nxcomp/include/NXvars.h new file mode 100644 index 000000000..f514000d7 --- /dev/null +++ b/nxcomp/include/NXvars.h @@ -0,0 +1,201 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef NXvars_H +#define NXvars_H + +/* + * This can be included by the proxy or another + * layer that doesn't use Xlib. + */ + +#if !defined(_XLIB_H_) && !defined(_XKBSRV_H_) + +#define NeedFunctionPrototypes 1 + +#define Display void + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Display flush policies. + */ + +#define NXPolicyImmediate 1 +#define NXPolicyDeferred 2 + +/* + * Type of flush. + */ + +#define NXFlushBuffer 0 +#define NXFlushLink 1 + +/* + * Type of statistics. + */ + +#define NXStatisticsPartial 0 +#define NXStatisticsTotal 1 + +/* + * Reason why the display is blocking. + */ + +#define NXBlockRead 1 +#define NXBlockWrite 2 + +/* + * Set if the client is interested in ignoring + * the display error and continue with the exe- + * cution of the program. By default the usual + * Xlib behaviour is gotten, and the library + * will call an exit(). + */ + +extern int _NXHandleDisplayError; + +/* + * The function below is called whenever Xlib is + * going to perform an I/O operation. The funct- + * ion can be redefined to include additional + * checks aimed at detecting if the display needs + * to be closed, for example because of an event + * or a signal mandating the end of the session. + * In this way the client program can regain the + * control before Xlib blocks waiting for input + * from the network. + */ + +typedef int (*NXDisplayErrorPredicate)( +#if NeedFunctionPrototypes + Display* /* display */, + int /* reason */ +#endif +); + +extern NXDisplayErrorPredicate _NXDisplayErrorFunction; + +/* + * This is called when Xlib is going to block + * waiting for the display to become readable or + * writable. The client can use the hook to run + * any arbitrary operation that may require some + * time to complete. The user should not try to + * read or write to the display inside the call- + * back routine. + */ + +typedef void (*NXDisplayBlockHandler)( +#if NeedFunctionPrototypes + Display* /* display */, + int /* reason */ +#endif +); + +extern NXDisplayBlockHandler _NXDisplayBlockFunction; + +/* + * Used to notify the program when more data + * is written to the socket. + */ + +typedef void (*NXDisplayWriteHandler)( +#if NeedFunctionPrototypes + Display* /* display */, + int /* length */ +#endif +); + +extern NXDisplayWriteHandler _NXDisplayWriteFunction; + +/* + * This callback is used to notify the agent + * that the proxy link has been flushed. + */ + +typedef void (*NXDisplayFlushHandler)( +#if NeedFunctionPrototypes + Display* /* display */, + int /* length */ +#endif +); + +extern NXDisplayFlushHandler _NXDisplayFlushFunction; + +/* + * Used by the NX transport to get an arbitrary + * string to add to its protocol statistics. + */ + +typedef void (*NXDisplayStatisticsHandler)( +#if NeedFunctionPrototypes + Display* /* display */, + char* /* buffer */, + int /* size */ +#endif +); + +extern NXDisplayStatisticsHandler _NXDisplayStatisticsFunction; + +/* + * Let users redefine the function printing an + * error message in the case of a out-of-order + * sequence number. + */ + +typedef void (*NXLostSequenceHandler)( +#if NeedFunctionPrototypes + Display* /* display */, + unsigned long /* newseq */, + unsigned long /* lastseq */, + unsigned int /* type */ +#endif +); + +extern NXLostSequenceHandler _NXLostSequenceFunction; + +/* + * Let the X server run the children processes + * (as for example the keyboard initialization + * utilities) by using the native system libra- + * ries, instead of the libraries shipped with + * the NX environment. If set, the Popen() in + * the X server will remove the LD_LIBRARY_PATH + * setting from the environment before calling + * the execl() function in the child process. + */ + +extern int _NXUnsetLibraryPath; + +#ifdef __cplusplus +} +#endif + +#endif /* NXvars_H */ diff --git a/nxcomp/install-sh b/nxcomp/install-sh deleted file mode 100755 index 58719246f..000000000 --- a/nxcomp/install-sh +++ /dev/null @@ -1,238 +0,0 @@ -#! /bin/sh -# -# install - install a program, script, or datafile -# This comes from X11R5. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. -# - - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" - - -# put in absolute paths if you don't have them in your path; or use env. vars. - -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" -mkdirprog="${MKDIRPROG-mkdir}" - -transformbasename="" -transform_arg="" -instcmd="$mvprog" -chmodcmd="$chmodprog 0755" -chowncmd="" -chgrpcmd="" -stripcmd="" -rmcmd="$rmprog -f" -mvcmd="$mvprog" -src="" -dst="" -dir_arg="" - -while [ x"$1" != x ]; do - case $1 in - -c) instcmd="$cpprog" - shift - continue;; - - -d) dir_arg=true - shift - continue;; - - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; - - -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; - - -s) stripcmd="$stripprog" - shift - continue;; - - -t=*) transformarg=`echo $1 | sed 's/-t=//'` - shift - continue;; - - -b=*) transformbasename=`echo $1 | sed 's/-b=//'` - shift - continue;; - - *) if [ x"$src" = x ] - then - src=$1 - else - # this colon is to work around a 386BSD /bin/sh bug - : - dst=$1 - fi - shift - continue;; - esac -done - -if [ x"$src" = x ] -then - echo "install: no input file specified" - exit 1 -else - true -fi - -if [ x"$dir_arg" != x ]; then - dst=$src - src="" - - if [ -d $dst ]; then - instcmd=: - else - instcmd=mkdir - fi -else - -# Waiting for this to be detected by the "$instcmd $src $dsttmp" command -# might cause directories to be created, which would be especially bad -# if $src (and thus $dsttmp) contains '*'. - - if [ -f $src -o -d $src ] - then - true - else - echo "install: $src does not exist" - exit 1 - fi - - if [ x"$dst" = x ] - then - echo "install: no destination specified" - exit 1 - else - true - fi - -# If destination is a directory, append the input filename; if your system -# does not like double slashes in filenames, you may need to add some logic - - if [ -d $dst ] - then - dst="$dst"/`basename $src` - else - true - fi -fi - -## this sed command emulates the dirname command -dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` - -# Make sure that the destination directory exists. -# this part is taken from Noah Friedman's mkinstalldirs script - -# Skip lots of stat calls in the usual case. -if [ ! -d "$dstdir" ]; then -defaultIFS=' -' -IFS="${IFS-${defaultIFS}}" - -oIFS="${IFS}" -# Some sh's can't handle IFS=/ for some reason. -IFS='%' -set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` -IFS="${oIFS}" - -pathcomp='' - -while [ $# -ne 0 ] ; do - pathcomp="${pathcomp}${1}" - shift - - if [ ! -d "${pathcomp}" ] ; - then - $mkdirprog "${pathcomp}" - else - true - fi - - pathcomp="${pathcomp}/" -done -fi - -if [ x"$dir_arg" != x ] -then - $doit $instcmd $dst && - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi -else - -# If we're going to rename the final executable, determine the name now. - - if [ x"$transformarg" = x ] - then - dstfile=`basename $dst` - else - dstfile=`basename $dst $transformbasename | - sed $transformarg`$transformbasename - fi - -# don't allow the sed command to completely eliminate the filename - - if [ x"$dstfile" = x ] - then - dstfile=`basename $dst` - else - true - fi - -# Make a temp file name in the proper directory. - - dsttmp=$dstdir/#inst.$$# - -# Move or copy the file name to the temp name - - $doit $instcmd $src $dsttmp && - - trap "rm -f ${dsttmp}" 0 && - -# and set any options; do chmod last to preserve setuid bits - -# If any of these fail, we abort the whole thing. If we want to -# ignore errors from any of these, just make sure not to ignore -# errors from the above "$doit $instcmd $src $dsttmp" command. - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && - -# Now rename the file to the real destination. - - $doit $rmcmd -f $dstdir/$dstfile && - $doit $mvcmd $dsttmp $dstdir/$dstfile - -fi && - - -exit 0 diff --git a/nxcomp/m4/nx-macros.m4 b/nxcomp/m4/nx-macros.m4 new file mode 120000 index 000000000..813e9b041 --- /dev/null +++ b/nxcomp/m4/nx-macros.m4 @@ -0,0 +1 @@ +../../m4/nx-macros.m4 \ No newline at end of file diff --git a/nxcomp/mkinstalldirs b/nxcomp/mkinstalldirs deleted file mode 100755 index 936cf3407..000000000 --- a/nxcomp/mkinstalldirs +++ /dev/null @@ -1,34 +0,0 @@ -#! /bin/sh -# mkinstalldirs --- make directory hierarchy -# Author: Noah Friedman -# Created: 1993-05-16 -# Last modified: 1995-03-05 -# Public domain - -errstatus=0 - -for file in ${1+"$@"} ; do - set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` - shift - - pathcomp= - for d in ${1+"$@"} ; do - pathcomp="$pathcomp$d" - case "$pathcomp" in - -* ) pathcomp=./$pathcomp ;; - esac - - if test ! -d "$pathcomp"; then - echo "mkdir $pathcomp" 1>&2 - mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? - fi - - if test ! -d "$pathcomp"; then - errstatus=$lasterr - fi - - pathcomp="$pathcomp/" - done -done - -exit $errstatus diff --git a/nxcomp/nxcomp.pc.in b/nxcomp/nxcomp.pc.in index f0963aa17..26206d857 100644 --- a/nxcomp/nxcomp.pc.in +++ b/nxcomp/nxcomp.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: nxcomp Description: NX Compression Library -Version: @VERSION@ +Version: @COMP_VERSION@ #libjepg does not provide a pkgconfig-file, zlib does not provide it for older versions #Requires: libjpeg zlib Requires: libpng diff --git a/nxcomp/src/ActionCache.cpp b/nxcomp/src/ActionCache.cpp new file mode 100644 index 000000000..783b1724e --- /dev/null +++ b/nxcomp/src/ActionCache.cpp @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Control.h" + +#include "ActionCache.h" + +ActionCache::ActionCache() +{ + for (int i = 0; i < 256; i++) + { + base_[i] = new IntCache(8); + } + + slot_ = 0; + last_ = 0; +} + +ActionCache::~ActionCache() +{ + for (int i = 0; i < 256; i++) + { + delete base_[i]; + } +} diff --git a/nxcomp/src/ActionCache.h b/nxcomp/src/ActionCache.h new file mode 100644 index 000000000..2aedd4a07 --- /dev/null +++ b/nxcomp/src/ActionCache.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ActionCache_H +#define ActionCache_H + +#include "IntCache.h" + +class ActionCache +{ + friend class EncodeBuffer; + friend class DecodeBuffer; + + public: + + ActionCache(); + ~ActionCache(); + + private: + + IntCache *base_[256]; + + unsigned int slot_; + unsigned short last_; +}; + +#endif /* ActionCache_H */ diff --git a/nxcomp/src/Agent.cpp b/nxcomp/src/Agent.cpp new file mode 100644 index 000000000..e55620601 --- /dev/null +++ b/nxcomp/src/Agent.cpp @@ -0,0 +1,84 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "Agent.h" +#include "Proxy.h" + +extern Proxy *proxy; + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +Agent::Agent(int fd[2]) +{ + remoteFd_ = fd[0]; + localFd_ = fd[1]; + + transport_ = new AgentTransport(localFd_); + + if (transport_ == NULL) + { + #ifdef PANIC + *logofs << "Agent: PANIC! Can't create the memory-to-memory transport " + << "for FD#" << localFd_ << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't create the memory-to-memory transport " + << "for FD#" << localFd_ << ".\n"; + + HandleCleanup(); + } + + FD_ZERO(&saveRead_); + FD_ZERO(&saveWrite_); + + canRead_ = 0; + + #ifdef DEBUG + *logofs << "Agent: Created agent object at " << this + << ".\n" << logofs_flush; + #endif +} + +Agent::~Agent() +{ + delete transport_; + + #ifdef DEBUG + *logofs << "Agent: Deleted agent object at " << this + << ".\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/Agent.h b/nxcomp/src/Agent.h new file mode 100644 index 000000000..3e1a50ae5 --- /dev/null +++ b/nxcomp/src/Agent.h @@ -0,0 +1,263 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Agent_H +#define Agent_H + +#include + +#include +#include +#include + +#include "Misc.h" +#include "Transport.h" +#include "Proxy.h" + +extern Proxy *proxy; + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +class Agent +{ + public: + + // + // Must be created by passing the fake descriptor that + // will be used for simulating socket communication + // betwen the agent and the proxy. I/O will take place + // by copying data to the agent's read and write buf- + // fers. + // + + Agent(int fd[2]); + + ~Agent(); + + AgentTransport *getTransport() const + { + return transport_; + } + + void saveReadMask(fd_set *readSet) + { + saveRead_ = *readSet; + } + + void saveWriteMask(fd_set *writeSet) + { + saveWrite_ = *writeSet; + } + + void clearReadMask(fd_set *readSet) + { + FD_CLR(remoteFd_, readSet); + FD_CLR(localFd_, readSet); + } + + void clearWriteMask(fd_set *writeSet) + { + FD_CLR(remoteFd_, writeSet); + FD_CLR(localFd_, writeSet); + } + + void setLocalRead(fd_set *readSet, int *result) + { + (*result)++; + + FD_SET(localFd_, readSet); + } + + void setRemoteRead(fd_set *readSet, int *result) + { + (*result)++; + + FD_SET(remoteFd_, readSet); + } + + void setRemoteWrite(fd_set *writeSet, int *result) + { + (*result)++; + + FD_SET(remoteFd_, writeSet); + } + + fd_set *getSavedReadMask() + { + return &saveRead_; + } + + fd_set *getSavedWriteMask() + { + return &saveWrite_; + } + + int getRemoteFd() const + { + return remoteFd_; + } + + int getLocalFd() const + { + return localFd_; + } + + int getProxyFd() const + { + return proxy -> getFd(); + } + + int isValid() const + { + return (transport_ != NULL); + } + + int localReadable() + { + return (transport_ -> readable() != 0); + } + + // + // Check if we can process more data from + // the agent descriptor and cache the result + // to avoid multiple calls. This must be + // always called before querying the other + // functions. + // + + void saveChannelState() + { + canRead_ = (proxy != NULL ? proxy -> canRead(localFd_) : 0); + } + + int remoteCanRead(const fd_set * const readSet) + { + // OS X 10.5 requires the second argument to be non-const, so copy readSet. + // It's safe though, as FD_ISSET does not operate on it. + fd_set readWorkSet = *readSet; + + #if defined(TEST) || defined(INFO) + *logofs << "Agent: remoteCanRead() is " << + (FD_ISSET(remoteFd_, &readWorkSet) && transport_ -> dequeuable() != 0) + << " with FD_ISSET() " << (int) FD_ISSET(remoteFd_, &readWorkSet) + << " and dequeuable " << transport_ -> dequeuable() + << ".\n" << logofs_flush; + #endif + + return (FD_ISSET(remoteFd_, &readWorkSet) && + transport_ -> dequeuable() != 0); + } + + int remoteCanWrite(const fd_set * const writeSet) + { + // OS X 10.5 requires the second argument to be non-const, so copy writeSet. + // It's safe though, as FD_ISSET does not operate on it. + fd_set writeWorkSet = *writeSet; + + #if defined(TEST) || defined(INFO) + *logofs << "Agent: remoteCanWrite() is " << + (FD_ISSET(remoteFd_, &writeWorkSet) && transport_ -> + queuable() != 0 && canRead_ == 1) << " with FD_ISSET() " + << (int) FD_ISSET(remoteFd_, &writeWorkSet) << " queueable " + << transport_ -> queuable() << " channel can read " + << canRead_ << ".\n" << logofs_flush; + #endif + + return (FD_ISSET(remoteFd_, &writeWorkSet) && + transport_ -> queuable() != 0 && + canRead_ == 1); + } + + int localCanRead() + { + #if defined(TEST) || defined(INFO) + *logofs << "Agent: localCanRead() is " << + (transport_ -> readable() != 0 && canRead_ == 1) + << " with readable " << transport_ -> readable() + << " channel can read " << canRead_ << ".\n" + << logofs_flush; + #endif + + return (transport_ -> readable() != 0 && + canRead_ == 1); + } + + int proxyCanRead() + { + #if defined(TEST) || defined(INFO) + *logofs << "Agent: proxyCanRead() is " << proxy -> canRead() + << ".\n" << logofs_flush; + #endif + + return (proxy -> canRead()); + } + + int proxyCanRead(const fd_set * const readSet) + { + // OS X 10.5 requires the second argument to be non-const, so copy readSet. + // It's safe though, as FD_ISSET does not operate on it. + fd_set readWorkSet = *readSet; + + #if defined(TEST) || defined(INFO) + *logofs << "Agent: proxyCanRead() is " + << ((int) FD_ISSET(proxy -> getFd(), &readWorkSet)) + << ".\n" << logofs_flush; + #endif + + return (FD_ISSET(proxy -> getFd(), &readWorkSet)); + } + + int enqueueData(const char *data, const int size) const + { + return transport_ -> enqueue(data, size); + } + + int dequeueData(char *data, int size) const + { + return transport_ -> dequeue(data, size); + } + + int dequeuableData() const + { + return transport_ -> dequeuable(); + } + + private: + + int remoteFd_; + int localFd_; + + fd_set saveRead_; + fd_set saveWrite_; + + int canRead_; + + AgentTransport *transport_; +}; + +#endif /* Agent_H */ diff --git a/nxcomp/src/Alpha.cpp b/nxcomp/src/Alpha.cpp new file mode 100644 index 000000000..6157e21e5 --- /dev/null +++ b/nxcomp/src/Alpha.cpp @@ -0,0 +1,138 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "Unpack.h" +#include "Alpha.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int UnpackAlpha(unsigned char method, unsigned char *src_data, int src_size, + unsigned char *dst_data, int dst_size) +{ + if (*src_data == 0) + { + if (dst_size != src_size - 1) + { + #ifdef TEST + *logofs << "UnpackAlpha: PANIC! Invalid destination size " + << dst_size << " with source " << src_size + << ".\n" << logofs_flush; + #endif + + return -1; + } + + #ifdef TEST + *logofs << "UnpackAlpha: Expanding " << src_size - 1 + << " bytes of plain alpha data.\n" << logofs_flush; + #endif + + memcpy(dst_data, src_data + 1, src_size - 1); + + return 1; + } + + unsigned int check_size = dst_size; + + int result = ZDecompress(&unpackStream, dst_data, &check_size, + src_data + 1, src_size - 1); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "UnpackAlpha: PANIC! Failure decompressing alpha data. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decompressing alpha data. " + << "Error is '" << zError(result) << "'.\n"; + + return -1; + } + else if (check_size != (unsigned int) dst_size) + { + #ifdef PANIC + *logofs << "UnpackAlpha: PANIC! Size mismatch in alpha data. " + << "Resulting size is " << check_size << " with " + << "expected size " << dst_size << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Size mismatch in alpha data. " + << "Resulting size is " << check_size << " with " + << "expected size " << dst_size << ".\n"; + + return -1; + } + + #ifdef TEST + *logofs << "UnpackAlpha: Decompressed " << src_size - 1 + << " bytes to " << dst_size << " bytes of alpha data.\n" + << logofs_flush; + #endif + + return 1; +} + +int UnpackAlpha(T_alpha *alpha, unsigned char *dst_data, + int dst_size, int big_endian) +{ + unsigned int count = dst_size >> 2; + + unsigned int i; + + int shift; + + if (count != alpha -> entries) + { + #ifdef WARNING + *logofs << "UnpackAlpha: WARNING! Not applying the alpha with " + << count << " elements needed and " << alpha -> entries + << " available.\n" << logofs_flush; + #endif + + return 0; + } + + shift = (big_endian == 1 ? 0 : 3); + + for (i = 0; i < count; i++) + { + *(dst_data + shift) = *(alpha -> data + i); + + dst_data += 4; + } + + return 1; +} diff --git a/nxcomp/src/Alpha.h b/nxcomp/src/Alpha.h new file mode 100644 index 000000000..ea5068812 --- /dev/null +++ b/nxcomp/src/Alpha.h @@ -0,0 +1,35 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Alpha_H +#define Alpha_H + +int UnpackAlpha(unsigned char method, unsigned char *src_data, int src_size, + unsigned char *dst_data, int dst_size); + +int UnpackAlpha(T_alpha *alpha, unsigned char *dst_data, + int dst_size, int big_endian); + +#endif /* Aplha_H */ diff --git a/nxcomp/src/Auth.cpp b/nxcomp/src/Auth.cpp new file mode 100644 index 000000000..d42c0556d --- /dev/null +++ b/nxcomp/src/Auth.cpp @@ -0,0 +1,671 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Auth.h" + +#include "Misc.h" +#include "Control.h" +#include "Timestamp.h" +#include "Pipe.h" + +#define DEFAULT_STRING_LIMIT 512 + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Store the provided cookie as our 'fake' cookie, then +// read the 'real' cookie from the current X authority +// file. +// + +Auth::Auth(char *display, char *cookie) +{ + display_ = NULL; + + file_ = NULL; + + last_ = nullTimestamp(); + + fakeCookie_ = NULL; + realCookie_ = NULL; + + fakeData_ = NULL; + realData_ = NULL; + + dataSize_ = 0; + + generatedCookie_ = 0; + + if (display == NULL || *display == '\0' || cookie == NULL || + *cookie == '\0' || strlen(cookie) != 32) + { + #ifdef PANIC + *logofs << "Auth: PANIC! Can't create the X authorization data " + << "with cookie '" << cookie << "' and display '" + << display << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't create the X authorization data " + << "with cookie '" << cookie << "' and display '" + << display << "'.\n"; + + return; + } + + #ifdef TEST + *logofs << "Auth: Creating X authorization data with cookie '" + << cookie << "' and display '" << display << "'.\n" + << logofs_flush; + #endif + + // + // Get a local copy of all parameters. + // + + display_ = new char[strlen(display) + 1]; + file_ = new char[DEFAULT_STRING_LIMIT]; + + fakeCookie_ = new char[strlen(cookie) + 1]; + realCookie_ = new char[DEFAULT_STRING_LIMIT]; + + if (display_ == NULL || file_ == NULL || + fakeCookie_ == NULL || realCookie_ == NULL) + { + #ifdef PANIC + *logofs << "Auth: PANIC! Cannot allocate memory for the X " + << "authorization data.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot allocate memory for the X " + << "authorization data.\n"; + + return; + } + + strcpy(display_, display); + + *file_ = '\0'; + + strcpy(fakeCookie_, cookie); + + *realCookie_ = '\0'; + + // + // Get the real cookie from the authorization file. + // + + updateCookie(); +} + +Auth::~Auth() +{ + delete [] display_; + delete [] file_; + + delete [] fakeCookie_; + delete [] realCookie_; + + delete [] fakeData_; + delete [] realData_; +} + +// +// At the present moment the cookie is read only once, +// at the time the instance is initialized. If the auth +// file changes along the life of the session, the old +// cookie will be used. This works with X servers beca- +// use of an undocumented "feature". See nx-X11. +// + +int Auth::updateCookie() +{ + if (isTimestamp(last_) == 0) + { + #ifdef TEST + *logofs << "Auth: Reading the X authorization file " + << "with last update at " << strMsTimestamp(last_) + << ".\n" << logofs_flush; + #endif + + if (getCookie() == 1 && validateCookie() == 1) + { + // + // It should rather be the modification time + // the auth file, so we can read it again if + // the file is changed. + // + + #ifdef TEST + *logofs << "Auth: Setting last X authorization file " + << "update at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + last_ = getTimestamp(); + + return 1; + } + + #ifdef PANIC + *logofs << "Auth: PANIC! Cannot read the cookie from the X " + << "authorization file.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot read the cookie from the X " + << "authorization file.\n"; + + return -1; + } + + #ifdef TEST + *logofs << "Auth: WARNING! Skipping check on the X " + << "authorization file.\n" << logofs_flush; + #endif + + return 0; +} + +int Auth::getCookie() +{ + // + // Check the name of the auth file that we are going to use. + // It can be either the value of the XAUTHORITY environment + // or the default .Xauthority file in the user's home. + // + + char *environment; + + environment = getenv("XAUTHORITY"); + + if (environment != NULL && *environment != '\0') + { + strncpy(file_, environment, DEFAULT_STRING_LIMIT - 1); + } + else + { + snprintf(file_, DEFAULT_STRING_LIMIT - 1, "%s/.Xauthority", + control -> HomePath); + } + + *(file_ + DEFAULT_STRING_LIMIT - 1) = '\0'; + + #ifdef TEST + *logofs << "Auth: Using X authorization file '" << file_ + << "'.\n" << logofs_flush; + #endif + + // + // Use the nxauth command on Windows and the Mac, xauth + // on all the other platforms. On Windows we assume that + // the nxauth command is located under bin in the client + // installation directory. On Mac OS X we assume that the + // command is located directly in the client installation + // directory, to make bundle shipping easier. On all the + // other platforms we use the default xauth command that + // is in our path. + // + + char command[DEFAULT_STRING_LIMIT]; + + #if defined(__CYGWIN32__) + + snprintf(command, DEFAULT_STRING_LIMIT - 1, + "%s/bin/nxauth", control -> SystemPath); + + *(command + DEFAULT_STRING_LIMIT - 1) = '\0'; + + #elif defined(__APPLE__) + + snprintf(command, DEFAULT_STRING_LIMIT - 1, + "%s/nxauth", control -> SystemPath); + + *(command + DEFAULT_STRING_LIMIT - 1) = '\0'; + + #else + + strcpy(command, "xauth"); + + #endif + + #ifdef TEST + *logofs << "Auth: Using X auth command '" << command + << "'.\n" << logofs_flush; + #endif + + // + // The SSH code forces using the unix:n port when passing localhost:n. + // This is probably because localhost:n can fail to return a valid + // entry on machines where the hostname for localhost doesn't match + // exactly the 'localhost' string. For example, on a freshly installed + // Fedora Core 3 I get a 'localhost.localdomain/unix:0' entry. Query- + // ing 'xauth list localhost:0' results in an empty result, while the + // query 'xauth list unix:0' works as expected. Note anyway that if + // the cookie for the TCP connection on 'localhost' is set to a dif- + // ferent cookie than the one for the Unix connections, both SSH and + // NX will match the wrong cookie and session will fail. + // + + char line[DEFAULT_STRING_LIMIT]; + + if (strncmp(display_, "localhost:", 10) == 0) + { + snprintf(line, DEFAULT_STRING_LIMIT, "unix:%s", display_ + 10); + } + else + { + snprintf(line, DEFAULT_STRING_LIMIT, "%.200s", display_); + } + + const char *parameters[256]; + + parameters[0] = command; + parameters[1] = command; + parameters[2] = "-f"; + parameters[3] = file_; + parameters[4] = "list"; + parameters[5] = line; + parameters[6] = NULL; + + #ifdef TEST + *logofs << "Auth: Executing command "; + + for (int i = 0; i < 256 && parameters[i] != NULL; i++) + { + *logofs << "[" << parameters[i] << "]"; + } + + *logofs << ".\n" << logofs_flush; + #endif + + // + // Use the popen() function to read the result + // of the command. We would better use our own + // implementation. + // + + FILE *data = Popen((char *const *) parameters, "r"); + + int result = -1; + + if (data == NULL) + { + #ifdef PANIC + *logofs << "Auth: PANIC! Failed to execute the X auth command.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed to execute the X auth command.\n"; + + goto AuthGetCookieResult; + } + + if (fgets(line, DEFAULT_STRING_LIMIT, data) == NULL) + { + #ifdef WARNING + *logofs << "Auth: WARNING! Failed to read data from the X " + << "auth command.\n" << logofs_flush; + #endif + + #ifdef TEST + cerr << "Warning" << ": Failed to read data from the X " + << "auth command.\n"; + #endif + + #ifdef PANIC + *logofs << "Auth: WARNING! Generating a fake cookie for " + << "X authentication.\n" << logofs_flush; + #endif + + #ifdef TEST + cerr << "Warning" << ": Generating a fake cookie for " + << "X authentication.\n"; + #endif + + generateCookie(realCookie_); + } + else + { + #ifdef TEST + *logofs << "Auth: Checking cookie in string '" << line + << "'.\n" << logofs_flush; + #endif + + // + // Skip the hostname in the authority entry + // just in case it includes some white spaces. + // + + char *cookie = NULL; + + cookie = index(line, ':'); + + if (cookie == NULL) + { + cookie = line; + } + + if (sscanf(cookie, "%*s %*s %511s", realCookie_) != 1) + { + #ifdef PANIC + *logofs << "Auth: PANIC! Failed to identify the cookie " + << "in string '" << line << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed to identify the cookie " + << "in string '" << line << "'.\n"; + + goto AuthGetCookieResult; + } + + #ifdef TEST + *logofs << "Auth: Got cookie '" << realCookie_ + << "' from file '" << file_ << "'.\n" + << logofs_flush; + #endif + } + + result = 1; + +AuthGetCookieResult: + + if (data != NULL) + { + Pclose(data); + } + + return result; +} + +int Auth::validateCookie() +{ + unsigned int length = strlen(realCookie_); + + if (length > DEFAULT_STRING_LIMIT / 2 - 1 || + strlen(fakeCookie_) != length) + { + #ifdef PANIC + *logofs << "Auth: PANIC! Size mismatch between cookies '" + << realCookie_ << "' and '" << fakeCookie_ << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Size mismatch between cookies '" + << realCookie_ << "' and '" << fakeCookie_ << "'.\n"; + + goto AuthValidateCookieError; + } + + // + // The length of the resulting data will be + // half the size of the Hex cookie. + // + + length = length / 2; + + fakeData_ = new char[length]; + realData_ = new char[length]; + + if (fakeData_ == NULL || realData_ == NULL) + { + #ifdef PANIC + *logofs << "Auth: PANIC! Cannot allocate memory for the binary X " + << "authorization data.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot allocate memory for the binary X " + << "authorization data.\n"; + + goto AuthValidateCookieError; + } + + // + // Translate the real cookie from Hex data + // to its binary representation. + // + + unsigned int value; + + for (unsigned int i = 0; i < length; i++) + { + if (sscanf(realCookie_ + 2 * i, "%2x", &value) != 1) + { + #ifdef PANIC + *logofs << "Auth: PANIC! Bad X authorization data in real " + << "cookie '" << realCookie_ << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Bad X authorization data in real cookie '" + << realCookie_ << "'.\n"; + + goto AuthValidateCookieError; + } + + realData_[i] = value; + + if (sscanf(fakeCookie_ + 2 * i, "%2x", &value) != 1) + { + #ifdef PANIC + *logofs << "Auth: PANIC! Bad X authorization data in fake " + << "cookie '" << fakeCookie_ << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Bad X authorization data in fake cookie '" + << fakeCookie_ << "'.\n"; + + goto AuthValidateCookieError; + } + + fakeData_[i] = value; + } + + dataSize_ = length; + + #ifdef TEST + *logofs << "Auth: Validated real cookie '" + << realCookie_ << "' and fake cookie '" << fakeCookie_ + << "' with data with size " << dataSize_ << ".\n" + << logofs_flush; + + *logofs << "Auth: Ready to accept incoming connections.\n" + << logofs_flush; + #endif + + return 1; + +AuthValidateCookieError: + + delete [] fakeData_; + delete [] realData_; + + fakeData_ = NULL; + realData_ = NULL; + + dataSize_ = 0; + + return -1; +} + +int Auth::checkCookie(unsigned char *buffer) +{ + if (isValid() != 1) + { + #ifdef PANIC + *logofs << "Auth: PANIC! Attempt to check the X cookie with " + << "invalid authorization data.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Attempt to check the X cookie with " + << "invalid authorization data.\n"; + + return -1; + } + + const char *protoName = "MIT-MAGIC-COOKIE-1"; + int protoSize = strlen(protoName); + + int matchedProtoSize; + int matchedDataSize; + + if (buffer[0] == 0x42) + { + // + // Byte order is MSB first. + // + + matchedProtoSize = 256 * buffer[6] + buffer[7]; + matchedDataSize = 256 * buffer[8] + buffer[9]; + } + else if (buffer[0] == 0x6c) + { + // + // Byte order is LSB first. + // + + matchedProtoSize = buffer[6] + 256 * buffer[7]; + matchedDataSize = buffer[8] + 256 * buffer[9]; + } + else + { + #ifdef WARNING + *logofs << "Auth: WARNING! Bad X connection data in the buffer.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Bad X connection data in the buffer.\n"; + + return -1; + } + + // + // Check if both the authentication protocol + // and the fake cookie match our data. + // + + int protoOffset = 12; + + #ifdef TEST + *logofs << "Auth: Received a protocol size of " + << matchedProtoSize << " bytes.\n" + << logofs_flush; + #endif + + if (matchedProtoSize != protoSize || + memcmp(buffer + protoOffset, protoName, protoSize) != 0) + { + #ifdef WARNING + *logofs << "Auth: WARNING! Protocol mismatch or no X " + << "authentication data.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Protocol mismatch or no X " + << "authentication data.\n"; + + return -1; + } + + int dataOffset = protoOffset + ((matchedProtoSize + 3) & ~3); + + #ifdef TEST + *logofs << "Auth: Received a data size of " + << matchedDataSize << " bytes.\n" + << logofs_flush; + #endif + + if (matchedDataSize != dataSize_ || + memcmp(buffer + dataOffset, fakeData_, dataSize_) != 0) + { + #ifdef WARNING + *logofs << "Auth: WARNING! Cookie mismatch in the X " + << "authentication data.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Cookie mismatch in the X " + << "authentication data.\n"; + + return -1; + } + + // + // Everything is OK. Replace the fake data. + // + + #ifdef TEST + *logofs << "Auth: Replacing fake X authentication data " + << "with the real data.\n" << logofs_flush; + #endif + + memcpy(buffer + dataOffset, realData_, dataSize_); + + return 1; +} + +void Auth::generateCookie(char *cookie) +{ + // + // Code is from the SSH implementation, except that + // we use a much weaker random number generator. + // This is not critical, anyway, as this is just a + // fake cookie. The X server doesn't have a cookie + // for the display, so it will ignore the value we + // feed to it. + // + + T_timestamp timer = getTimestamp(); + + srand((unsigned int) timer.tv_usec); + + unsigned int data = rand(); + + for (int i = 0; i < 16; i++) + { + if (i % 4 == 0) + { + data = rand(); + } + + snprintf(cookie + 2 * i, 3, "%02x", data & 0xff); + + data >>= 8; + } + + generatedCookie_ = 1; + + #ifdef TEST + *logofs << "Auth: Generated X cookie string '" + << cookie << "'.\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/Auth.h b/nxcomp/src/Auth.h new file mode 100644 index 000000000..d51d9a26f --- /dev/null +++ b/nxcomp/src/Auth.h @@ -0,0 +1,127 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Auth_H +#define Auth_H + +#include "Timestamp.h" + +// +// Handle the forwarding of authorization credentials +// to the X server by replacing the fake cookie with +// the real cookie as it is read from the auth file. +// At the moment only the MIT-MAGIC-COOKIE-1 cookies +// are recognized. The implementation is based on the +// corresponding code found in the SSH client. +// + +class Auth +{ + public: + + // + // Must be created by passing the fake cookie that + // will be forwarded by the remote end and with the + // real X display that is going to be used for the + // session. + // + + Auth(char *display, char *cookie); + + ~Auth(); + + int isValid() + { + return (isTimestamp(last_) == 1 && fakeCookie_ != NULL && + *fakeCookie_ != '\0' && realCookie_ != NULL && + *realCookie_ != '\0' && fakeData_ != NULL && + realData_ != NULL && dataSize_ != 0); + } + + int isFake() const + { + return generatedCookie_; + } + + // + // Method called in the channel class to find if the + // provided cookie matches the fake one. If the data + // matches, the fake cookie is replaced with the real + // one. + // + + int checkCookie(unsigned char *buffer); + + protected: + + // + // Update the real cookie for the display. If called + // a further time, check if the auth file is changed + // and get the new cookie. + // + + int updateCookie(); + + // + // Find out which authorization file is to be used + // and query the cookie for the current display. + // + + int getCookie(); + + // + // Extract the binary data from the cookies so that + // data can be directly compared at the time it is + // taken from the X request. + // + + int validateCookie(); + + // + // Generate a fake random cookie and copy it to the + // provided string. + // + + void generateCookie(char *cookie); + + private: + + char *display_; + char *file_; + + T_timestamp last_; + + char *fakeCookie_; + char *realCookie_; + + char *fakeData_; + char *realData_; + + int dataSize_; + + int generatedCookie_; +}; + +#endif /* Auth_H */ diff --git a/nxcomp/src/Bitmap.cpp b/nxcomp/src/Bitmap.cpp new file mode 100644 index 000000000..c89df53e3 --- /dev/null +++ b/nxcomp/src/Bitmap.cpp @@ -0,0 +1,118 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "Bitmap.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int UnpackBitmap(T_geometry *geometry, unsigned char method, unsigned char *src_data, + int src_size, int dst_bpp, int dst_width, int dst_height, + unsigned char *dst_data, int dst_size) +{ + if (dst_bpp != 32) + { + #ifdef TEST + *logofs << "UnpackBitmap: Nothing to do with " + << "image of " << dst_bpp << " bits per plane " + << "and size " << src_size << ".\n" + << logofs_flush; + #endif + + if (src_size != dst_size) + { + #ifdef PANIC + *logofs << "UnpackBitmap: PANIC! Size mismatch with " + << src_size << " bytes in the source and " + << dst_size << " in the destination.\n" + << logofs_flush; + #endif + + return -1; + } + + memcpy(dst_data, src_data, src_size); + + return 1; + } + else if (src_size != dst_width * dst_height * 3 || + dst_size != dst_width * dst_height * 4) + { + #ifdef PANIC + *logofs << "UnpackBitmap: PANIC! Size mismatch with " + << src_size << " bytes in the source and " + << dst_size << " in the destination.\n" + << logofs_flush; + #endif + + return -1; + } + + /* + * Insert the 4th byte in the bitmap. + */ + + unsigned char *next_src = src_data; + unsigned char *next_dst = dst_data; + + if (geometry -> image_byte_order == LSBFirst) + { + while (next_src < src_data + src_size) + { + *next_dst++ = *next_src++; + *next_dst++ = *next_src++; + *next_dst++ = *next_src++; + + next_dst++; + } + } + else + { + while (next_src < src_data + src_size) + { + next_dst++; + + *next_dst++ = *next_src++; + *next_dst++ = *next_src++; + *next_dst++ = *next_src++; + } + } + + #ifdef TEST + *logofs << "UnpackBitmap: Unpacked " << src_size + << " bytes to a buffer of " << dst_size + << " with " << dst_bpp << " bits per plane.\n" + << logofs_flush; + #endif + + return 1; +} diff --git a/nxcomp/src/Bitmap.h b/nxcomp/src/Bitmap.h new file mode 100644 index 000000000..8143e3125 --- /dev/null +++ b/nxcomp/src/Bitmap.h @@ -0,0 +1,36 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Bitmap_H +#define Bitmap_H + +#include "Unpack.h" + +int UnpackBitmap(T_geometry *geometry, unsigned char method, + unsigned char *src_data, int src_size, int dst_bpp, + int dst_width, int dst_height, unsigned char *dst_data, + int dst_size); + +#endif /* Bitmap_H */ diff --git a/nxcomp/src/BlockCache.cpp b/nxcomp/src/BlockCache.cpp new file mode 100644 index 000000000..161145e3d --- /dev/null +++ b/nxcomp/src/BlockCache.cpp @@ -0,0 +1,81 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "BlockCache.h" + + +int BlockCache::compare(unsigned int size, const unsigned char *data, + int overwrite) +{ + int match = 0; + if (size == size_) + { + match = 1; + for (unsigned int i = 0; i < size_; i++) + if (data[i] != buffer_[i]) + { + match = 0; + break; + } + } + if (!match && overwrite) + set(size, data); + return match; +} + + +void BlockCache::set(unsigned int size, const unsigned char *data) +{ + if (size_ < size) + { + delete[]buffer_; + buffer_ = new unsigned char[size]; + } + size_ = size; + memcpy(buffer_, data, size); + checksum_ = checksum(size, data); +} + + +unsigned int BlockCache::checksum(unsigned int size, const unsigned char *data) +{ + unsigned int sum = 0; + unsigned int shift = 0; + const unsigned char *next = data; + for (unsigned int i = 0; i < size; i++) + { + unsigned int value = (unsigned int) *next++; + sum += (value << shift); + shift++; + if (shift == 8) + shift = 0; + } + return sum; +} diff --git a/nxcomp/src/BlockCache.h b/nxcomp/src/BlockCache.h new file mode 100644 index 000000000..48e586966 --- /dev/null +++ b/nxcomp/src/BlockCache.h @@ -0,0 +1,67 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef BlockCache_H +#define BlockCache_H + + +// Cache to hold an arbitrary-length block of bytes + +class BlockCache +{ + public: + BlockCache():buffer_(0), size_(0), checksum_(0) + { + } + ~BlockCache() + { + delete[]buffer_; + } + int compare(unsigned int size, const unsigned char *data, + int overwrite = 1); + void set(unsigned int size, const unsigned char *data); + + unsigned int getLength() const + { + return size_; + } + unsigned int getChecksum() const + { + return checksum_; + } + const unsigned char *getData() const + { + return buffer_; + } + + static unsigned int checksum(unsigned int size, const unsigned char *data); + +private: + unsigned char *buffer_; + unsigned int size_; + unsigned int checksum_; +}; + +#endif /* BlockCache_H */ diff --git a/nxcomp/src/BlockCacheSet.cpp b/nxcomp/src/BlockCacheSet.cpp new file mode 100644 index 000000000..1dd6361dc --- /dev/null +++ b/nxcomp/src/BlockCacheSet.cpp @@ -0,0 +1,147 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "BlockCacheSet.h" + + +BlockCacheSet::BlockCacheSet(unsigned int numCaches): + caches_(new BlockCache *[numCaches]), size_(numCaches), + length_(0) +{ + for (unsigned int i = 0; i < numCaches; i++) + caches_[i] = new BlockCache(); +} + + +BlockCacheSet::~BlockCacheSet() +{ + // + // TODO: There is still a strange segfault occurring + // at random time under Cygwin, when proxy is being + // shutdown. Problem appeared just after upgrading + // to the latest version of the Cygwin DLL. A stack + // trace, obtained at the last minute, reveals that + // failure happens in this destructor. + // + + #ifndef __CYGWIN32__ + + for (unsigned int i = 0; i < size_; i++) + delete caches_[i]; + delete[]caches_; + + #endif /* ifdef __CYGWIN32__ */ +} + + +int +BlockCacheSet::lookup(unsigned int dataLength, const unsigned char *data, + unsigned int &index) +{ + unsigned int checksum = BlockCache::checksum(dataLength, data); + for (unsigned int i = 0; i < length_; i++) + if ((caches_[i]->getChecksum() == checksum) && + (caches_[i]->compare(dataLength, data, 0))) + { + // match + index = i; + if (i) + { + BlockCache *save = caches_[i]; + unsigned int target = (i >> 1); + do + { + caches_[i] = caches_[i - 1]; + i--; + } + while (i > target); + caches_[target] = save; + } + return 1; + } + // no match + unsigned int insertionPoint = (length_ >> 1); + unsigned int start; + if (length_ >= size_) + start = size_ - 1; + else + { + start = length_; + length_++; + } + BlockCache *save = caches_[start]; + for (unsigned int k = start; k > insertionPoint; k--) + caches_[k] = caches_[k - 1]; + caches_[insertionPoint] = save; + save->set(dataLength, data); + return 0; +} + + +void +BlockCacheSet::get(unsigned index, unsigned int &size, + const unsigned char *&data) +{ + size = caches_[index]->getLength(); + data = caches_[index]->getData(); + if (index) + { + BlockCache *save = caches_[index]; + unsigned int target = (index >> 1); + do + { + caches_[index] = caches_[index - 1]; + index--; + } + while (index > target); + caches_[target] = save; + } +} + + + +void +BlockCacheSet::set(unsigned int dataLength, const unsigned char *data) +{ + unsigned int insertionPoint = (length_ >> 1); + unsigned int start; + if (length_ >= size_) + start = size_ - 1; + else + { + start = length_; + length_++; + } + BlockCache *save = caches_[start]; + for (unsigned int k = start; k > insertionPoint; k--) + caches_[k] = caches_[k - 1]; + caches_[insertionPoint] = save; + save->set(dataLength, data); +} diff --git a/nxcomp/src/BlockCacheSet.h b/nxcomp/src/BlockCacheSet.h new file mode 100644 index 000000000..97273b0e0 --- /dev/null +++ b/nxcomp/src/BlockCacheSet.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef BlockCacheSet_H +#define BlockCacheSet_H + +#include "BlockCache.h" + + +class BlockCacheSet +{ + public: + BlockCacheSet(unsigned int numCaches); + ~BlockCacheSet(); + + int lookup(unsigned int size, const unsigned char *data, + unsigned int &index); + void get(unsigned int index, unsigned int &size, const unsigned char *&data); + void set(unsigned int size, const unsigned char *data); + + private: + BlockCache ** caches_; + unsigned int size_; + unsigned int length_; +}; + +#endif /* BlockCacheSet_H */ diff --git a/nxcomp/src/ChangeGC.cpp b/nxcomp/src/ChangeGC.cpp new file mode 100644 index 000000000..e92178f27 --- /dev/null +++ b/nxcomp/src/ChangeGC.cpp @@ -0,0 +1,184 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ChangeGC.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int ChangeGCStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ChangeGCMessage *changeGC = (ChangeGCMessage *) message; + + // + // Here is the fingerprint. + // + + changeGC -> gcontext = GetULONG(buffer + 4, bigEndian); + changeGC -> value_mask = GetULONG(buffer + 8, bigEndian); + + // + // Clear the unused bytes carried in the + // payload to increase the effectiveness + // of the caching algorithm. + // + + if ((int) size > dataOffset) + { + #ifdef DEBUG + *logofs << name() << ": Removing unused bytes from the " + << "data payload.\n" << logofs_flush; + #endif + + changeGC -> value_mask &= (1 << 23) - 1; + + unsigned int mask = 0x1; + unsigned char *source = (unsigned char *) buffer + CHANGEGC_DATA_OFFSET; + unsigned long value = 0; + + for (unsigned int i = 0; i < 23; i++) + { + if (changeGC -> value_mask & mask) + { + value = GetULONG(source, bigEndian); + + value &= (0xffffffff >> (32 - CREATEGC_FIELD_WIDTH[i])); + + PutULONG(value, source, bigEndian); + + source += 4; + } + + mask <<= 1; + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int ChangeGCStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ChangeGCMessage *changeGC = (ChangeGCMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(changeGC -> gcontext, buffer + 4, bigEndian); + PutULONG(changeGC -> value_mask, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void ChangeGCStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + ChangeGCMessage *changeGC = (ChangeGCMessage *) message; + + *logofs << name() << ": Identity gcontext " << changeGC -> gcontext + << ", mask " << changeGC -> value_mask << ", size " + << changeGC -> size_ << ".\n" << logofs_flush; + #endif +} + +void ChangeGCStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +/* + md5_append(md5_state_, buffer + 4, 8); +*/ + md5_append(md5_state_, buffer + 8, 4); +} + +void ChangeGCStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + ChangeGCMessage *changeGC = (ChangeGCMessage *) message; + ChangeGCMessage *cachedChangeGC = (ChangeGCMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << changeGC -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(changeGC -> gcontext, clientCache -> gcCache); + + cachedChangeGC -> gcontext = changeGC -> gcontext; +} + +void ChangeGCStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + ChangeGCMessage *changeGC = (ChangeGCMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + changeGC -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << changeGC -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/ChangeGC.h b/nxcomp/src/ChangeGC.h new file mode 100644 index 000000000..9cac90e66 --- /dev/null +++ b/nxcomp/src/ChangeGC.h @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ChangeGC_H +#define ChangeGC_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define CHANGEGC_ENABLE_CACHE 1 +#define CHANGEGC_ENABLE_DATA 0 +#define CHANGEGC_ENABLE_SPLIT 0 +#define CHANGEGC_ENABLE_COMPRESS 0 + +#define CHANGEGC_DATA_LIMIT 144 +#define CHANGEGC_DATA_OFFSET 12 + +#define CHANGEGC_CACHE_SLOTS 3000 +#define CHANGEGC_CACHE_THRESHOLD 3 +#define CHANGEGC_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class ChangeGCMessage : public Message +{ + friend class ChangeGCStore; + + public: + + ChangeGCMessage() + { + } + + ~ChangeGCMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int gcontext; + unsigned int value_mask; +}; + +class ChangeGCStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + ChangeGCStore() : MessageStore() + { + enableCache = CHANGEGC_ENABLE_CACHE; + enableData = CHANGEGC_ENABLE_DATA; + enableSplit = CHANGEGC_ENABLE_SPLIT; + enableCompress = CHANGEGC_ENABLE_COMPRESS; + + dataLimit = CHANGEGC_DATA_LIMIT; + dataOffset = CHANGEGC_DATA_OFFSET; + + cacheSlots = CHANGEGC_CACHE_SLOTS; + cacheThreshold = CHANGEGC_CACHE_THRESHOLD; + cacheLowerThreshold = CHANGEGC_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~ChangeGCStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "ChangeGC"; + } + + virtual unsigned char opcode() const + { + return X_ChangeGC; + } + + virtual unsigned int storage() const + { + return sizeof(ChangeGCMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new ChangeGCMessage(); + } + + virtual Message *create(const Message &message) const + { + return new ChangeGCMessage((const ChangeGCMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (ChangeGCMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; +}; + +#endif /* ChangeGC_H */ diff --git a/nxcomp/src/ChangeProperty.cpp b/nxcomp/src/ChangeProperty.cpp new file mode 100644 index 000000000..74814c2ea --- /dev/null +++ b/nxcomp/src/ChangeProperty.cpp @@ -0,0 +1,191 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ChangeProperty.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int ChangePropertyStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; + + changeProperty -> mode = *(buffer + 1); + changeProperty -> format = *(buffer + 16); + + changeProperty -> window = GetULONG(buffer + 4, bigEndian); + changeProperty -> property = GetULONG(buffer + 8, bigEndian); + changeProperty -> type = GetULONG(buffer + 12, bigEndian); + changeProperty -> length = GetULONG(buffer + 20, bigEndian); + + // + // Cleanup the padding bytes. + // + + unsigned int uiFormat; + unsigned int uiLengthInBytes; + + if ((int) size > CHANGEPROPERTY_DATA_OFFSET) + { + uiFormat = *(buffer + 16); + + uiLengthInBytes = changeProperty -> length; + + #ifdef DEBUG + *logofs << name() << ": length " << uiLengthInBytes + << ", format " << uiFormat << ", size " + << size << ".\n" << logofs_flush; + #endif + + if (uiFormat == 16) + { + uiLengthInBytes <<= 1; + } + else if (uiFormat == 32) + { + uiLengthInBytes <<= 2; + } + + unsigned char *end = ((unsigned char *) buffer) + size; + unsigned char *pad = ((unsigned char *) buffer) + CHANGEPROPERTY_DATA_OFFSET + uiLengthInBytes; + + CleanData((unsigned char *) pad, end - pad); + } + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int ChangePropertyStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; + + *(buffer + 1) = changeProperty -> mode; + *(buffer + 16) = changeProperty -> format; + + PutULONG(changeProperty -> window, buffer + 4, bigEndian); + PutULONG(changeProperty -> property, buffer + 8, bigEndian); + PutULONG(changeProperty -> type, buffer + 12, bigEndian); + PutULONG(changeProperty -> length, buffer + 20, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void ChangePropertyStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; + + *logofs << name() << ": Identity mode " << (unsigned int) changeProperty -> mode << ", format " + << (unsigned int) changeProperty -> format << ", window " << changeProperty -> window + << ", property " << changeProperty -> property << ", type " << changeProperty -> type + << ", length " << changeProperty -> length << ", size " << changeProperty -> size_ + << ".\n" << logofs_flush; + + #endif +} + +void ChangePropertyStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 1, 1); + md5_append(md5_state_, buffer + 16, 1); + + md5_append(md5_state_, buffer + 8, 4); + md5_append(md5_state_, buffer + 12, 4); + md5_append(md5_state_, buffer + 20, 4); +} + +void ChangePropertyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; + ChangePropertyMessage *cachedChangeProperty = (ChangePropertyMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << changeProperty -> window + << " as window field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(changeProperty -> window, clientCache -> windowCache); + + cachedChangeProperty -> window = changeProperty -> window; +} + +void ChangePropertyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + ChangePropertyMessage *changeProperty = (ChangePropertyMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> windowCache); + + changeProperty -> window = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << changeProperty -> window + << " as window field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/ChangeProperty.h b/nxcomp/src/ChangeProperty.h new file mode 100644 index 000000000..c06ce10fc --- /dev/null +++ b/nxcomp/src/ChangeProperty.h @@ -0,0 +1,189 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ChangeProperty_H +#define ChangeProperty_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define CHANGEPROPERTY_ENABLE_CACHE 1 +#define CHANGEPROPERTY_ENABLE_DATA 0 +#define CHANGEPROPERTY_ENABLE_SPLIT 0 +#define CHANGEPROPERTY_ENABLE_COMPRESS 0 + +#define CHANGEPROPERTY_DATA_LIMIT 28688 +#define CHANGEPROPERTY_DATA_OFFSET 24 + +#define CHANGEPROPERTY_CACHE_SLOTS 2000 +#define CHANGEPROPERTY_CACHE_THRESHOLD 2 +#define CHANGEPROPERTY_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class ChangePropertyMessage : public Message +{ + friend class ChangePropertyStore; + + public: + + ChangePropertyMessage() + { + } + + ~ChangePropertyMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char mode; + unsigned char format; + unsigned int window; + unsigned int property; + unsigned int type; + unsigned int length; +}; + +class ChangePropertyStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + ChangePropertyStore() : MessageStore() + { + enableCache = CHANGEPROPERTY_ENABLE_CACHE; + enableData = CHANGEPROPERTY_ENABLE_DATA; + enableSplit = CHANGEPROPERTY_ENABLE_SPLIT; + enableCompress = CHANGEPROPERTY_ENABLE_COMPRESS; + + dataLimit = CHANGEPROPERTY_DATA_LIMIT; + dataOffset = CHANGEPROPERTY_DATA_OFFSET; + + cacheSlots = CHANGEPROPERTY_CACHE_SLOTS; + cacheThreshold = CHANGEPROPERTY_CACHE_THRESHOLD; + cacheLowerThreshold = CHANGEPROPERTY_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~ChangePropertyStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "ChangeProperty"; + } + + virtual unsigned char opcode() const + { + return X_ChangeProperty; + } + + virtual unsigned int storage() const + { + return sizeof(ChangePropertyMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new ChangePropertyMessage(); + } + + virtual Message *create(const Message &message) const + { + return new ChangePropertyMessage((const ChangePropertyMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (ChangePropertyMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* ChangeProperty_H */ diff --git a/nxcomp/src/Channel.cpp b/nxcomp/src/Channel.cpp new file mode 100644 index 000000000..24a422e37 --- /dev/null +++ b/nxcomp/src/Channel.cpp @@ -0,0 +1,2039 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Channel.h" + +#include "List.h" +#include "Proxy.h" +#include "Statistics.h" + +#include "StaticCompressor.h" + +#include "NXalert.h" + +extern Proxy *proxy; + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Log the operations related to splits. +// + +#undef SPLIT + +#undef COUNT + +#define COUNT_MAJOR_OPCODE 154 + +#undef MONITOR + +#define MONITOR_MAJOR_OPCODE 154 +#define MONITOR_MINOR_OPCODE 23 + +#undef CLEAR + +#define CLEAR_MAJOR_OPCODE 154 +#define CLEAR_MINOR_OPCODE 23 + +// +// Define this to know how many messages +// are allocated and deallocated. +// + +#undef REFERENCES + +// +// Set to the descriptor of the first X +// channel successfully connected. +// + +int Channel::firstClient_ = -1; + +// +// Port used for font server connections. +// + +int Channel::fontPort_ = -1; + +// +// This is used for reference count. +// + +#ifdef REFERENCES + +int Channel::references_ = 0; + +#endif + +Channel::Channel(Transport *transport, StaticCompressor *compressor) + + : transport_(transport), compressor_(compressor) +{ + fd_ = transport_ -> fd(); + + finish_ = 0; + closing_ = 0; + drop_ = 0; + congestion_ = 0; + priority_ = 0; + + alert_ = 0; + + firstRequest_ = 1; + firstReply_ = 1; + + enableCache_ = 1; + enableSplit_ = 1; + enableSave_ = 1; + enableLoad_ = 1; + + // + // Must be set by proxy. + // + + opcodeStore_ = NULL; + + clientStore_ = NULL; + serverStore_ = NULL; + + clientCache_ = NULL; + serverCache_ = NULL; + + #ifdef REFERENCES + *logofs << "Channel: Created new Channel at " + << this << " out of " << ++references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +Channel::~Channel() +{ + if (firstClient_ == fd_) + { + firstClient_ = -1; + } + + #ifdef REFERENCES + *logofs << "Channel: Deleted Channel at " + << this << " out of " << --references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +int Channel::handleEncode(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, + MessageStore *store, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + #ifdef MONITOR + + static float totalMessages = 0; + static float totalBits = 0; + + int bits; + int diff; + + bits = encodeBuffer.getBits(); + + #endif + + // + // Check if message can be differentially + // encoded using a similar message in the + // message store. + // + + #ifdef COUNT + + if (*(buffer) == COUNT_MAJOR_OPCODE) + { + if (*(buffer) < 128) + { + *logofs << "handleEncode: Handling OPCODE#" << (unsigned int) *(buffer) + << ".\n" << logofs_flush; + } + else + { + *logofs << "handleEncode: Handling OPCODE#" << (unsigned int) *(buffer) + << " MINOR#" << (unsigned int) *(buffer + 1) << ".\n" + << logofs_flush; + } + } + + #endif + + #ifdef CLEAR + + if (*(buffer) == CLEAR_MAJOR_OPCODE && + (CLEAR_MINOR_OPCODE == -1 || *(buffer + 1) == CLEAR_MINOR_OPCODE)) + { + *((unsigned char *) buffer) = X_NoOperation; + + *((unsigned char *) buffer + 1) = '\0'; + + CleanData((unsigned char *) buffer + 4, size - 4); + } + + #endif + + if (handleEncodeCached(encodeBuffer, channelCache, + store, buffer, size) == 1) + { + #ifdef MONITOR + + diff = encodeBuffer.getBits() - bits; + + if (*(buffer) == MONITOR_MAJOR_OPCODE && + (MONITOR_MINOR_OPCODE == -1 || *(buffer + 1) == MONITOR_MINOR_OPCODE)) + { + totalMessages++; + + totalBits += diff; + + *logofs << "handleEncode: Handled cached OPCODE#" << (unsigned int) *(buffer) + << " MINOR#" << (unsigned int) *(buffer + 1) << ". " << size + << " bytes in, " << diff << " bits (" << ((float) diff) / 8 + << " bytes) out. Average " << totalBits / totalMessages + << "/1.\n" << logofs_flush; + } + + #endif + + // + // Let the channel update the split store + // and notify the agent in the case of a + // cache hit. + // + + if (store -> enableSplit) + { + handleSplit(encodeBuffer, store, store -> lastAction, + store -> lastHit, opcode, buffer, size); + } + + return 1; + } + + // + // A similar message could not be found in + // cache or message must be discarded. Must + // transmit the message using the field by + // field differential encoding. + // + + handleEncodeIdentity(encodeBuffer, channelCache, + store, buffer, size, bigEndian_); + + // + // Check if message has a distinct data part. + // + + if (store -> enableData) + { + // + // If message split was requested by agent then send data + // out-of-band, dividing it in small chunks. Until message + // is completely transferred, keep in the split store a + // dummy version of the message, with data replaced with a + // pattern. + // + // While data is being transferred, agent should have put + // the resource (for example its client) asleep. It can + // happen, though, that a different client would reference + // the same message. We cannot issue a cache hit for images + // being split (such images are put in store in 'incomplete' + // state), so we need to handle this case. + // + + if (store -> enableSplit == 1) + { + // + // Let the channel decide what to do with the + // message. If the split can't take place be- + // cause the split store is full, the channel + // will tell the remote side that the data is + // going to follow. + // + + if (handleSplit(encodeBuffer, store, store -> lastAction, + (store -> lastAction == IS_ADDED ? store -> lastAdded : 0), + opcode, buffer, size) == 1) + { + #ifdef MONITOR + + diff = encodeBuffer.getBits() - bits; + + if (*(buffer) == MONITOR_MAJOR_OPCODE && + (MONITOR_MINOR_OPCODE == -1 || *(buffer + 1) == MONITOR_MINOR_OPCODE)) + { + totalMessages++; + + totalBits += diff; + + *logofs << "handleEncode: Handled split OPCODE#" << (unsigned int) *(buffer) + << " MINOR#" << (unsigned int) *(buffer + 1) << ". " << size + << " bytes in, " << diff << " bits (" << ((float) diff) / 8 + << " bytes) out. Average " << totalBits / totalMessages + << "/1.\n" << logofs_flush; + } + + #endif + + return 0; + } + } + + // + // The split did not take place and we are going + // to transfer the data part. Check if the static + // compression of the data section is enabled. + // This is the case of all messages not having a + // special differential encoding or messages that + // we want to store in cache in compressed form. + // + + unsigned int offset = store -> identitySize(buffer, size); + + if (store -> enableCompress) + { + unsigned char *data = NULL; + unsigned int dataSize = 0; + + int compressed = handleCompress(encodeBuffer, opcode, offset, + buffer, size, data, dataSize); + if (compressed < 0) + { + return -1; + } + else if (compressed > 0) + { + // + // Update the size of the message according + // to the result of the data compression. + // + + handleUpdate(store, size - offset, dataSize); + } + } + else + { + handleCopy(encodeBuffer, opcode, offset, buffer, size); + } + } + + #ifdef MONITOR + + diff = encodeBuffer.getBits() - bits; + + if (*(buffer) == MONITOR_MAJOR_OPCODE && + (MONITOR_MINOR_OPCODE == -1 || *(buffer + 1) == MONITOR_MINOR_OPCODE)) + { + totalMessages++; + + totalBits += diff; + + *logofs << "handleEncode: Handled OPCODE#" << (unsigned int) *(buffer) + << " MINOR#" << (unsigned int) *(buffer + 1) << ". " << size + << " bytes in, " << diff << " bits (" << ((float) diff) / 8 + << " bytes) out. Average " << totalBits / totalMessages + << "/1.\n" << logofs_flush; + } + + #endif + + return 0; +} + +int Channel::handleDecode(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, + MessageStore *store, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + // + // Check first if the message is in the + // message store. + // + + unsigned int split = 0; + + if (handleDecodeCached(decodeBuffer, channelCache, + store, buffer, size) == 1) + { + // + // Let the channel update the split store + // in the case of a message being cached. + // + + if (store -> enableSplit == 1) + { + // Since ProtoStep7 (#issue 108) + #ifdef DEBUG + *logofs << "handleDecode: " << store -> name() + << ": Checking if the message was split.\n" + << logofs_flush; + #endif + + decodeBuffer.decodeBoolValue(split); + + if (split == 1) + { + handleSplit(decodeBuffer, store, store -> lastAction, + store -> lastHit, opcode, buffer, size); + + handleCleanAndNullRequest(opcode, buffer, size); + } + } + + return 1; + } + + // + // Decode the full identity. + // + + handleDecodeIdentity(decodeBuffer, channelCache, store, buffer, + size, bigEndian_, &writeBuffer_); + + // + // Check if the message has a distinct + // data part. + // + + if (store -> enableData) + { + // + // Check if message has been split. + // + + if (store -> enableSplit) + { + #ifdef DEBUG + *logofs << "handleDecode: " << store -> name() + << ": Checking if the message was split.\n" + << logofs_flush; + #endif + + decodeBuffer.decodeBoolValue(split); + + if (split == 1) + { + // + // If the message was added to the store, + // create the entry without the data part. + // + + handleSaveSplit(store, buffer, size); + + handleSplit(decodeBuffer, store, store -> lastAction, + (store -> lastAction == IS_ADDED ? store -> lastAdded : 0), + opcode, buffer, size); + + handleCleanAndNullRequest(opcode, buffer, size); + + return 0; + } + } + + // + // Decode the data part. + // + + unsigned int offset = store -> identitySize(buffer, size); + + if (store -> enableCompress) + { + const unsigned char *data = NULL; + unsigned int dataSize = 0; + + int decompressed = handleDecompress(decodeBuffer, opcode, offset, + buffer, size, data, dataSize); + if (decompressed < 0) + { + return -1; + } + else if (decompressed > 0) + { + // + // The message has been transferred + // in compressed format. + // + + handleSave(store, buffer, size, data, dataSize); + + if (store -> enableSplit) + { + if (split == 1) + { + handleSplit(decodeBuffer, store, store -> lastAction, + (store -> lastAction == IS_ADDED ? store -> lastAdded : 0), + opcode, buffer, size); + + handleCleanAndNullRequest(opcode, buffer, size); + } + } + + return 0; + } + } + else + { + // + // Static compression of the data part + // was not enabled for this message. + // + + handleCopy(decodeBuffer, opcode, offset, buffer, size); + } + } + + // + // The message doesn't have a data part + // or the data was not compressed. + // + + handleSave(store, buffer, size); + + if (store -> enableSplit) + { + if (split == 1) + { + handleSplit(decodeBuffer, store, store -> lastAction, + (store -> lastAction == IS_ADDED ? store -> lastAdded : 0), + opcode, buffer, size); + + handleCleanAndNullRequest(opcode, buffer, size); + } + } + + return 0; +} + +int Channel::handleEncodeCached(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, + MessageStore *store, const unsigned char *buffer, + const unsigned int size) +{ + if (control -> LocalDeltaCompression == 0 || + enableCache_ == 0 || store -> enableCache == 0) + { + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeActionValue(is_discarded, + store -> lastActionCache); + + store -> lastAction = is_discarded; + + return 0; + } + + #ifdef DEBUG + *logofs << "handleEncodeCached: " << store -> name() + << ": Going to handle a new message of this class.\n" + << logofs_flush; + #endif + + // + // Check if the estimated size of cache is greater + // than the requested limit. If it is the case make + // some room by deleting one or more messages. + // + + int position; + + while (mustCleanStore(store) == 1 && canCleanStore(store) == 1) + { + #ifdef DEBUG + *logofs << "handleEncodeCached: " << store -> name() + << ": Trying to reduce size of message store.\n" + << logofs_flush; + #endif + + position = store -> clean(use_checksum); + + if (position == nothing) + { + #ifdef TEST + *logofs << "handleEncodeCached: " << store -> name() + << ": WARNING! No message found to be " + << "actually removed.\n" << logofs_flush; + #endif + + break; + } + + #ifdef DEBUG + *logofs << "handleEncodeCached: " << store -> name() + << ": Message at position " << position + << " will be removed.\n" << logofs_flush; + #endif + + // + // Encode the position of message to + // be discarded. + // + + store -> lastRemoved = position; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeActionValue(is_removed, store -> lastRemoved, + store -> lastActionCache); + + #ifdef DEBUG + *logofs << "handleEncodeCached: " << store -> name() << ": Going to " + << "clean up message at position " << position << ".\n" + << logofs_flush; + #endif + + store -> remove(position, use_checksum, discard_data); + + #ifdef DEBUG + *logofs << "handleEncodeCached: " << store -> name() << ": There are " + << store -> getSize() << " messages in the store out of " + << store -> cacheSlots << " slots.\n" << logofs_flush; + + *logofs << "handleEncodeCached: " << store -> name() + << ": Size of store is " << store -> getLocalStorageSize() + << " bytes locally and " << store -> getRemoteStorageSize() + << " bytes remotely.\n" << logofs_flush; + + *logofs << "handleEncodeCached: " << store -> name() + << ": Size of total cache is " << store -> getLocalTotalStorageSize() + << " bytes locally and " << store -> getRemoteTotalStorageSize() + << " bytes remotely.\n" << logofs_flush; + #endif + } + + #ifdef DEBUG + + if (mustCleanStore(store) == 1 && canCleanStore(store) == 0) + { + *logofs << "handleEncodeCached: " << store -> name() + << ": Store would need a clean but operation will be delayed.\n" + << logofs_flush; + + *logofs << "handleEncodeCached: " << store -> name() << ": There are " + << store -> getSize() << " messages in the store out of " + << store -> cacheSlots << " slots.\n" << logofs_flush; + + *logofs << "handleEncodeCached: " << store -> name() + << ": Size of store is " << store -> getLocalStorageSize() + << " bytes locally and " << store -> getRemoteStorageSize() + << " bytes remotely.\n" << logofs_flush; + + *logofs << "handleEncodeCached: " << store -> name() + << ": Size of total cache is " << store -> getLocalTotalStorageSize() + << " bytes locally and " << store -> getRemoteTotalStorageSize() + << " bytes remotely.\n" << logofs_flush; + } + + #endif + + // + // If 'on the wire' size of message exceeds the + // allowed limit then avoid to store it in the + // cache. + // + + if (store -> validateMessage(buffer, size) == 0) + { + #ifdef TEST + *logofs << "handleEncodeCached: " << store -> name() + << ": Message with size " << size << " ignored.\n" + << logofs_flush; + #endif + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeActionValue(is_discarded, + store -> lastActionCache); + + store -> lastAction = is_discarded; + + return 0; + } + + // + // Fill the message object with the + // received data. + // + + Message *message = store -> getTemporary(); + + if (message == NULL) + { + #ifdef PANIC + *logofs << "handleEncodeCached: " << store -> name() + << ": PANIC! Can't allocate memory for " + << "a new message.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory for " + << "a new message in context [D].\n"; + + HandleCleanup(); + } + + // + // As we are at encoding side, it is enough to store the + // checksum for the object while data can be erased. Both + // the identity and the data will never be sent through + // the wire again as long as they are stored in the cache + // at the decoding side. The split parameter is always + // set to 0 as the data will not be stored in any case. + // + + store -> parse(message, 0, buffer, size, use_checksum, + discard_data, bigEndian_); + + #ifdef DUMP + + store -> dump(message); + + #endif + + // + // Search the object in the message + // store. If found get the position. + // + + #ifdef DEBUG + *logofs << "handleEncodeCached: " << store -> name() + << ": Searching object of size " << size + << " in the cache.\n" << logofs_flush; + #endif + + int added; + int locked; + + position = store -> findOrAdd(message, use_checksum, + discard_data, added, locked); + + if (position == nothing) + { + #ifdef WARNING + *logofs << "handleEncodeCached: " << store -> name() + << ": WARNING! Can't store object in the cache.\n" + << logofs_flush; + #endif + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeActionValue(is_discarded, + store -> lastActionCache); + + store -> lastAction = is_discarded; + + return 0; + } + else if (locked == 1) + { + // + // We can't issue a cache hit. Encoding identity + // differences while message it's being split + // would later result in agent to commit a wrong + // version of message. + // + + #ifdef WARNING + *logofs << "handleEncodeCached: " << store -> name() + << ": WARNING! Message of size " << store -> plainSize(position) + << " at position " << position << " is locked.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Message of size " << store -> plainSize(position) + << " at position " << position << " is locked.\n"; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeActionValue(is_discarded, + store -> lastActionCache); + + store -> lastAction = is_discarded; + + return 0; + } + else if (added == 1) + { + store -> resetTemporary(); + + #ifdef DEBUG + *logofs << "handleEncodeCached: " << store -> name() << ": Message of size " + << store -> plainSize(position) << " has been stored at position " + << position << ".\n" << logofs_flush; + + *logofs << "handleEncodeCached: " << store -> name() << ": There are " + << store -> getSize() << " messages in the store out of " + << store -> cacheSlots << " slots.\n" << logofs_flush; + + *logofs << "handleEncodeCached: " << store -> name() + << ": Size of store is " << store -> getLocalStorageSize() + << " bytes locally and " << store -> getRemoteStorageSize() + << " bytes remotely.\n" << logofs_flush; + + *logofs << "handleEncodeCached: " << store -> name() + << ": Size of total cache is " << store -> getLocalTotalStorageSize() + << " bytes locally and " << store -> getRemoteTotalStorageSize() + << " bytes remotely.\n" << logofs_flush; + #endif + + // + // Inform the decoding side that message + // must be inserted in cache and encode + // the position where the insertion took + // place. + // + + store -> lastAction = IS_ADDED; + + store -> lastAdded = position; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeActionValue(IS_ADDED, store -> lastAdded, + store -> lastActionCache); + + return 0; + } + else + { + #ifdef DEBUG + *logofs << "handleEncodeCached: " << store -> name() + << ": Cache hit. Found object at position " + << position << ".\n" << logofs_flush; + #endif + + // + // Must abort the connection if the + // the position is invalid. + // + + Message *cachedMessage = store -> get(position); + + // + // Increase the rating of the cached + // message. + // + + store -> touch(cachedMessage); + + #ifdef DEBUG + *logofs << "handleEncodeCached: " << store -> name() << ": Hits for " + << "object at position " << position << " are now " + << store -> getTouches(position) << ".\n" + << logofs_flush; + #endif + + // + // Send to the decoding side position + // where object can be found in cache. + // + + store -> lastAction = IS_HIT; + + store -> lastHit = position; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeActionValue(IS_HIT, store -> lastHit, + store -> lastActionCache); + + // + // Send the field by field differences in + // respect to the original message stored + // in cache. + // + + store -> updateIdentity(encodeBuffer, message, cachedMessage, channelCache); + + return 1; + } +} + +void Channel::handleUpdateAdded(MessageStore *store, unsigned int dataSize, + unsigned int compressedDataSize) +{ + #ifdef TEST + + if (store -> lastAction != IS_ADDED) + { + #ifdef PANIC + *logofs << "handleUpdateAdded: " << store -> name() + << ": PANIC! Function called for action '" + << store -> lastAction << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Update function called for " + << "store '" << store -> name() << "' with " + << "action '" << store -> lastAction + << "'.\n"; + + HandleCleanup(); + } + + #endif + + #ifdef DEBUG + *logofs << "handleUpdateAdded: " << store -> name() << ": Updating " + << "object at position " << store -> lastAdded << " of size " + << store -> plainSize(store -> lastAdded) << " (" << dataSize + << "/" << compressedDataSize << ").\n" << logofs_flush; + #endif + + store -> updateData(store -> lastAdded, dataSize, compressedDataSize); + + #ifdef DEBUG + *logofs << "handleUpdateAdded: " << store -> name() << ": There are " + << store -> getSize() << " messages in the store out of " + << store -> cacheSlots << " slots.\n" << logofs_flush; + + *logofs << "handleUpdateAdded: " << store -> name() + << ": Size of store is " << store -> getLocalStorageSize() + << " bytes locally and " << store -> getRemoteStorageSize() + << " bytes remotely.\n" << logofs_flush; + + *logofs << "handleUpdateAdded: " << store -> name() + << ": Size of total cache is " << store -> getLocalTotalStorageSize() + << " bytes locally and " << store -> getRemoteTotalStorageSize() + << " bytes remotely.\n" << logofs_flush; + #endif +} + +int Channel::handleDecodeCached(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, + MessageStore *store, unsigned char *&buffer, + unsigned int &size) +{ + // + // Create a new message object and + // fill it with received data. + // + + #ifdef DEBUG + *logofs << "handleDecodeCached: " << store -> name() + << ": Going to handle a new message of this class.\n" + << logofs_flush; + #endif + + // + // Decode bits telling how to handle + // this message. + // + + unsigned char action; + unsigned short int position; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeActionValue(action, position, + store -> lastActionCache); + + // + // Clean operations must always come + // before any operation on message. + // + + while (action == is_removed) + { + // Since ProtoStep7 (#issue 108) + store -> lastRemoved = position; + + #ifdef DEBUG + + if (store -> get(store -> lastRemoved)) + { + *logofs << "handleDecodeCached: " << store -> name() << ": Cleaning up " + << "object at position " << store -> lastRemoved + << " of size " << store -> plainSize(store -> lastRemoved) + << " (" << store -> plainSize(store -> lastRemoved) << "/" + << store -> compressedSize(store -> lastRemoved) << ").\n" + << logofs_flush; + } + + #endif + + // + // If the message can't be found we + // will abort the connection. + // + + store -> remove(store -> lastRemoved, discard_checksum, use_data); + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeActionValue(action, position, + store -> lastActionCache); + } + + // + // If it's a cache hit, the position + // where object can be found follows. + // + + if ((T_store_action) action == IS_HIT) + { + // Since ProtoStep7 (#issue 108) + store -> lastHit = position; + + // + // Get data from the cache at given position. + // + + #ifdef DEBUG + + if (store -> get(store -> lastHit)) + { + *logofs << "handleDecodeCached: " << store -> name() << ": Retrieving " + << "object at position " << store -> lastHit + << " of size " << store -> plainSize(store -> lastHit) + << " (" << store -> plainSize(store -> lastHit) << "/" + << store -> compressedSize(store -> lastHit) << ").\n" + << logofs_flush; + } + + #endif + + // + // Must abort the connection if the + // the position is invalid. + // + + Message *message = store -> get(store -> lastHit); + + // + // Make room for the outgoing message. + // + + size = store -> plainSize(store -> lastHit); + + buffer = writeBuffer_.addMessage(size); + + #ifdef DEBUG + *logofs << "handleDecodeCached: " << store -> name() + << ": Prepared an outgoing buffer of " + << size << " bytes.\n" << logofs_flush; + #endif + + // + // Decode the variant part. Pass client + // or server cache to the message store. + // + + store -> updateIdentity(decodeBuffer, message, channelCache); + + // + // Write each field in the outgoing buffer. + // + + store -> unparse(message, buffer, size, bigEndian_); + + #ifdef DUMP + + store -> dump(message); + + #endif + + store -> lastAction = IS_HIT; + + return 1; + } + else if ((T_store_action) action == IS_ADDED) + { + // Since ProtoStep7 (#issue 108) + store -> lastAdded = position; + + #ifdef DEBUG + *logofs << "handleDecodeCached: " << store -> name() + << ": Message will be later stored at position " + << store -> lastAdded << ".\n" << logofs_flush; + #endif + + store -> lastAction = IS_ADDED; + + return 0; + } + else + { + #ifdef DEBUG + *logofs << "handleDecodeCached: " << store -> name() + << ": Message will be later discarded.\n" + << logofs_flush; + #endif + + store -> lastAction = is_discarded; + + return 0; + } +} + +void Channel::handleSaveAdded(MessageStore *store, int split, unsigned char *buffer, + unsigned int size, const unsigned char *compressedData, + const unsigned int compressedDataSize) +{ + #ifdef TEST + + if (store -> lastAction != IS_ADDED) + { + #ifdef PANIC + *logofs << "handleSaveAdded: " << store -> name() + << ": PANIC! Function called for action '" + << store -> lastAction << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Save function called for " + << "store '" << store -> name() << "' with " + << "action '" << store -> lastAction + << "'.\n"; + + HandleCleanup(); + } + + #endif + + Message *message = store -> getTemporary(); + + if (message == NULL) + { + #ifdef PANIC + *logofs << "handleSaveAdded: " << store -> name() + << ": PANIC! Can't access temporary storage " + << "for message at position " << store -> lastAdded + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't access temporary storage " + << "for message at position " << store -> lastAdded + << ".\n"; + + HandleCleanup(); + } + + if (compressedData == NULL) + { + // + // If the data part has been split + // avoid to copy it into the message. + // + + store -> parse(message, split, buffer, size, discard_checksum, + use_data, bigEndian_); + } + else + { + store -> parse(message, buffer, size, compressedData, + compressedDataSize, discard_checksum, + use_data, bigEndian_); + } + + if (store -> add(message, store -> lastAdded, + discard_checksum, use_data) == nothing) + { + #ifdef PANIC + *logofs << "handleSaveAdded: " << store -> name() + << ": PANIC! Can't store message in the cache " + << "at position " << store -> lastAdded << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't store message of type " + << store -> name() << "in the cache at position " + << store -> lastAdded << ".\n"; + + HandleCleanup(); + } + else + { + store -> resetTemporary(); + + #ifdef DEBUG + *logofs << "handleSaveAdded: " << store -> name() << ": Stored " + << (compressedData == NULL ? "plain" : "compressed") + << " object at position " << store -> lastAdded + << " of size " << store -> plainSize(store -> lastAdded) + << " (" << store -> plainSize(store -> lastAdded) << "/" + << store -> compressedSize(store -> lastAdded) << ").\n" + << logofs_flush; + #endif + } + + #ifdef DEBUG + *logofs << "handleSaveAdded: " << store -> name() + << ": Size of store is " << store -> getLocalStorageSize() + << " bytes locally and " << store -> getRemoteStorageSize() + << " bytes remotely.\n" << logofs_flush; + + *logofs << "handleSaveAdded: " << store -> name() + << ": Size of total cache is " << store -> getLocalTotalStorageSize() + << " bytes locally and " << store -> getRemoteTotalStorageSize() + << " bytes remotely.\n" << logofs_flush; + #endif +} + +int Channel::handleWait(int timeout) +{ + #ifdef TEST + *logofs << "handleWait: Going to wait for more data " + << "on FD#" << fd_ << " at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + T_timestamp startTs = getNewTimestamp(); + + T_timestamp nowTs = startTs; + + int readable; + int remaining; + + for (;;) + { + remaining = timeout - diffTimestamp(startTs, nowTs); + + if (transport_ -> blocked() == 1) + { + #ifdef WARNING + *logofs << "handleWait: WARNING! Having to drain with " + << "channel " << "for FD#" << fd_ << " blocked.\n" + << logofs_flush; + #endif + + handleDrain(0, remaining); + + continue; + } + + if (remaining <= 0) + { + #ifdef TEST + *logofs << "handleWait: Timeout raised while waiting " + << "for more data for FD#" << fd_ << " at " + << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + return 0; + } + + #ifdef TEST + *logofs << "handleWait: Waiting " << remaining << " Ms " + << "for a new message on FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + readable = transport_ -> wait(remaining); + + if (readable > 0) + { + #ifdef TEST + *logofs << "handleWait: WARNING! Encoding more data " + << "for FD#" << fd_ << " at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + if (proxy -> handleAsyncRead(fd_) < 0) + { + return -1; + } + + return 1; + } + else if (readable == -1) + { + return -1; + } + + nowTs = getNewTimestamp(); + } +} + +int Channel::handleDrain(int limit, int timeout) +{ + #ifdef TEST + *logofs << "handleDrain: Going to drain FD#" << fd_ + << " with a limit of " << limit << " bytes " + << "at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + T_timestamp startTs = getNewTimestamp(); + + T_timestamp nowTs = startTs; + + int drained; + int remaining; + + int result; + + for (;;) + { + remaining = timeout - diffTimestamp(startTs, nowTs); + + if (remaining <= 0) + { + #ifdef TEST + *logofs << "handleDrain: Timeout raised while draining " + << "FD#" << fd_ << " at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + result = 0; + + goto ChannelDrainEnd; + } + + #ifdef TEST + *logofs << "handleDrain: Trying to write to FD#" + << fd_ << " with " << remaining << " Ms " + << "remaining.\n" << logofs_flush; + #endif + + drained = transport_ -> drain(limit, remaining); + + if (drained == 1) + { + #ifdef TEST + *logofs << "handleDrain: Transport for FD#" << fd_ + << " drained to " << transport_ -> length() + << " bytes at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + result = 1; + + goto ChannelDrainEnd; + } + else if (drained == 0 && transport_ -> readable() > 0) + { + #ifdef TEST + *logofs << "handleDrain: WARNING! Encoding more data " + << "for FD#" << fd_ << " at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + if (proxy -> handleAsyncRead(fd_) < 0) + { + goto ChannelDrainError; + } + } + else if (drained == -1) + { + goto ChannelDrainError; + } + + nowTs = getNewTimestamp(); + + if (diffTimestamp(startTs, nowTs) >= control -> ChannelTimeout) + { + int seconds = (remaining + control -> LatencyTimeout * 10) / 1000; + + #ifdef WARNING + *logofs << "handleDrain: WARNING! Could not drain FD#" + << fd_ << " within " << seconds << " seconds.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Can't write to connection on FD#" + << fd_ << " since " << seconds << " seconds.\n"; + + if (alert_ == 0) + { + if (control -> ProxyMode == proxy_client) + { + alert_ = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT; + } + else + { + alert_ = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT; + } + + HandleAlert(alert_, 1); + } + } + } + +ChannelDrainEnd: + + // + // Maybe we drained the channel and are + // now out of the congestion state. + // + + handleCongestion(); + + return result; + +ChannelDrainError: + + finish_ = 1; + + return -1; +} + +int Channel::handleCongestion() +{ + // + // Send a begin congestion control code + // if the local end of the channel does + // not consume its data. + // + + if (isCongested() == 1) + { + if (congestion_ == 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleCongestion: Sending congestion for FD#" + << fd_ << " with length " << transport_ -> length() + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + congestion_ = 1; + + // + // Use the callback to send the control + // code immediately. + // + + if (proxy -> handleAsyncCongestion(fd_) < 0) + { + finish_ = 1; + + return -1; + } + } + } + else + { + // + // If the channel was in congestion state + // send an end congestion control code. + // + + if (congestion_ == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleCongestion: Sending decongestion for FD#" + << fd_ << " with length " << transport_ -> length() + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + congestion_ = 0; + + if (proxy -> handleAsyncDecongestion(fd_) < 0) + { + finish_ = 1; + + return -1; + } + } + + // + // Remove the "channel unresponsive" + // dialog. + // + + if (alert_ != 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleCongestion: Displacing the dialog " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + HandleAlert(DISPLACE_MESSAGE_ALERT, 1); + } + } + + return 1; +} + +int Channel::handleFlush(T_flush type, int bufferLength, int scratchLength) +{ + if (finish_ == 1) + { + #ifdef TEST + *logofs << "handleFlush: Not flushing data for " + << "finishing channel for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + writeBuffer_.fullReset(); + + return -1; + } + + #ifdef TEST + *logofs << "handleFlush: Flushing " << bufferLength + << " + " << scratchLength << " bytes " + << "to FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + // + // Check if the channel has data available. + // Recent Linux kernels are very picky. + // They require that we read often or they + // assume that the process is non-interact- + // ive. + // + + int result = 0; + + if (handleAsyncEvents() < 0) + { + goto ChannelFlushError; + } + + // + // Write the data in the main buffer first, + // followed by the data in the scratch buffer. + // + + if (bufferLength > 0) + { + result = transport_ -> write(write_immediate, + writeBuffer_.getData(), bufferLength); + } + + if (result >= 0 && scratchLength > 0) + { + result = transport_ -> write(write_immediate, + writeBuffer_.getScratchData(), scratchLength); + } + + if (type == flush_if_any) + { + writeBuffer_.fullReset(); + } + else + { + writeBuffer_.partialReset(); + } + + // + // If we failed to write to the X connection then + // set the finish flag. The caller should continue + // to handle all the remaining messages or it will + // corrupt the decode buffer. At the real end, an + // error will be propagated to the upper layers + // which will perform any needed cleanup. + // + + if (result < 0) + { + goto ChannelFlushError; + } + + // + // Reset transport buffers. + // + + transport_ -> partialReset(); + + // + // Check if the X server has generated + // any event in response to our data. + // + + if (handleAsyncEvents() < 0) + { + goto ChannelFlushError; + } + + // + // Check if the channel has entered in + // congestion state and, in this case, + // send an immediate congestion control + // code to the remote. + // + + handleCongestion(); + + // + // We could optionally drain the output + // buffer if this is X11 channel. + // + // if (isCongested() == 1 && isReliable() == 1) + // { + // if (handleDrain(0, control -> ChannelTimeout) < 0) + // { + // goto ChannelFlushError; + // } + // } + // + + return 1; + +ChannelFlushError: + + finish_ = 1; + + return -1; +} + +int Channel::handleFlush() +{ + #ifdef TEST + *logofs << "handleFlush: Flushing " + << transport_ -> length() << " bytes to FD#" + << fd_ << " with descriptor writable.\n" + << logofs_flush; + #endif + + // + // Check if there is anything to read + // before anf after having written to + // the socket. + // + + if (handleAsyncEvents() < 0) + { + goto ChannelFlushError; + } + + if (transport_ -> flush() < 0) + { + #ifdef TEST + *logofs << "handleFlush: Failure detected " + << "flushing data to FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + goto ChannelFlushError; + } + + if (handleAsyncEvents() < 0) + { + goto ChannelFlushError; + } + + // + // Reset channel's transport buffers. + // + + transport_ -> partialReset(); + + // + // Check if the channel went out of the + // congestion state. + // + + handleCongestion(); + + return 1; + +ChannelFlushError: + + finish_ = 1; + + return -1; +} + +void Channel::handleResetAlert() +{ + if (alert_ != 0) + { + #ifdef TEST + *logofs << "handleResetAlert: The channel alert '" + << alert_ << "' was displaced.\n" + << logofs_flush; + #endif + + alert_ = 0; + } +} + +int Channel::handleCompress(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned int offset, const unsigned char *buffer, + const unsigned int size, unsigned char *&compressedData, + unsigned int &compressedDataSize) +{ + if (size <= offset) + { + #ifdef DEBUG + *logofs << "handleCompress: Not compressing data for FD#" << fd_ + << " as offset is " << offset << " with data size " + << size << ".\n" << logofs_flush; + #endif + + return 0; + } + + #ifdef DEBUG + *logofs << "handleCompress: Compressing data for FD#" << fd_ + << " with data size " << size << " and offset " + << offset << ".\n" << logofs_flush; + #endif + + // + // It is responsibility of the compressor to + // mark the buffer as such if the compression + // couldn't take place. + // + + if (compressor_ -> compressBuffer(buffer + offset, size - offset, compressedData, + compressedDataSize, encodeBuffer) <= 0) + { + #ifdef DEBUG + *logofs << "handleCompress: Sent " << size - offset + << " bytes of plain data for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + return 0; + } + else + { + #ifdef DEBUG + *logofs << "handleCompress: Sent " << compressedDataSize + << " bytes of compressed data for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + return 1; + } +} + +int Channel::handleDecompress(DecodeBuffer &decodeBuffer, const unsigned char opcode, + const unsigned int offset, unsigned char *buffer, + const unsigned int size, const unsigned char *&compressedData, + unsigned int &compressedDataSize) +{ + if (size <= offset) + { + return 0; + } + + int result = compressor_ -> decompressBuffer(buffer + offset, size - offset, + compressedData, compressedDataSize, + decodeBuffer); + if (result < 0) + { + #ifdef PANIC + *logofs << "handleDecompress: PANIC! Failed to decompress " + << size - offset << " bytes of data for FD#" << fd_ + << " with OPCODE#" << (unsigned int) opcode << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Data decompression failed for OPCODE#" + << (unsigned int) opcode << ".\n"; + + return -1; + } + else if (result == 0) + { + #ifdef DEBUG + *logofs << "handleDecompress: Received " << size - offset + << " bytes of plain data for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + return 0; + } + else + { + #ifdef DEBUG + *logofs << "handleDecompress: Received " << compressedDataSize + << " bytes of compressed data for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + return 1; + } +} + +int Channel::handleCleanAndNullRequest(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size) +{ + #ifdef TEST + *logofs << "handleCleanAndNullRequest: Removing the previous data " + << "and sending an X_NoOperation " << "for FD#" << fd_ + << " due to OPCODE#" << (unsigned int) opcode << " (" + << DumpOpcode(opcode) << ").\n" << logofs_flush; + #endif + + writeBuffer_.removeMessage(size - 4); + + size = 4; + opcode = X_NoOperation; + + return 1; +} + +int Channel::handleNullRequest(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size) +{ + #ifdef TEST + *logofs << "handleNullRequest: Sending an X_NoOperation for FD#" + << fd_ << " due to OPCODE#" << (unsigned int) opcode + << " (" << DumpOpcode(opcode) << ").\n" + << logofs_flush; + #endif + + size = 4; + buffer = writeBuffer_.addMessage(size); + opcode = X_NoOperation; + + return 1; +} + +void Channel::handleSplitStoreError(int resource) +{ + if (resource < 0 || resource >= CONNECTIONS_LIMIT) + { + #ifdef PANIC + *logofs << "handleSplitStoreError: PANIC! Resource " + << resource << " is out of range with limit " + << "set to " << CONNECTIONS_LIMIT << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Resource " << resource + << " is out of range with limit set to " + << CONNECTIONS_LIMIT << ".\n"; + + HandleCleanup(); + } + else + { + #ifdef PANIC + *logofs << "handleSplitStoreError: PANIC! Cannot " + << "allocate the split store for resource " + << resource << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot allocate the " + << "split store for resource " << resource + << ".\n"; + + HandleCleanup(); + } +} + +void Channel::handleSplitStoreAlloc(List *list, int resource) +{ + if (resource < 0 || resource >= CONNECTIONS_LIMIT) + { + handleSplitStoreError(resource); + } + + if (clientStore_ -> getSplitStore(resource) == NULL) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitStoreAlloc: Allocating a new " + << "split store for resource " << resource + << ".\n" << logofs_flush; + #endif + + SplitStore *splitStore = clientStore_ -> createSplitStore(resource); + + if (splitStore == NULL) + { + handleSplitStoreError(resource); + } + + list -> add(resource); + } + #if defined(TEST) || defined(SPLIT) + else + { + // + // Old proxy versions only use a single + // split store. + // + + if (resource != 0) + { + *logofs << "handleSplitStoreAlloc: WARNING! A split " + << "store for resource " << resource + << " already exists.\n" << logofs_flush; + } + } + #endif +} + +void Channel::handleSplitStoreRemove(List *list, int resource) +{ + if (resource < 0 || resource >= CONNECTIONS_LIMIT) + { + handleSplitStoreError(resource); + } + + SplitStore *splitStore = clientStore_ -> getSplitStore(resource); + + if (splitStore != NULL) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitStoreRemove: Deleting the " + << "split store for resource " << resource + << ".\n" << logofs_flush; + #endif + + clientStore_ -> destroySplitStore(resource); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitStoreRemove: Deleting resource " + << resource << " from the list " << ".\n" + << logofs_flush; + #endif + + list -> remove(resource); + } + #if defined(TEST) || defined(SPLIT) + else + { + *logofs << "handleSplitStoreRemove: WARNING! A split " + << "store for resource " << resource + << " does not exist.\n" << logofs_flush; + } + #endif +} + +Split *Channel::handleSplitCommitRemove(int request, int resource, int position) +{ + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitCommitRemove: SPLIT! Checking split " + << "commit with resource " << resource << " request " + << request << " and position " << position + << ".\n" << logofs_flush; + #endif + + // + // Remove the split from the split queue. + // + + CommitStore *commitStore = clientStore_ -> getCommitStore(); + + Split *split = commitStore -> pop(); + + if (split == NULL) + { + #ifdef PANIC + *logofs << "handleSplitCommitRemove: PANIC! Can't " + << "find the split in the commit queue.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't find the " + << "split in the commit queue.\n"; + + HandleCleanup(); + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitCommitRemove: SPLIT! Element from " + << "the queue has resource " << split -> getResource() + << " request " << split -> getRequest() << " and " + << "position " << split -> getPosition() + << ".\n" << logofs_flush; + #endif + + // Since ProtoStep7 (#issue 108) + if (resource != split -> getResource() || + request != split -> getRequest() || + position != split -> getPosition()) + { + #ifdef PANIC + *logofs << "handleSplitCommitRemove: PANIC! The data in " + << "the split doesn't match the commit request.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": The data in the split doesn't " + << "match the commit request.\n"; + + return NULL; + } + + #if defined(TEST) || defined(SPLIT) + + commitStore -> dump(); + + #endif + + return split; +} + +int Channel::setReferences() +{ + #ifdef TEST + *logofs << "Channel: Initializing the static " + << "members for the base class.\n" + << logofs_flush; + #endif + + firstClient_ = -1; + + fontPort_ = -1; + + #ifdef REFERENCES + + references_ = 0; + + #endif + + return 1; +} + +int Channel::setOpcodes(OpcodeStore *opcodeStore) +{ + opcodeStore_ = opcodeStore; + + #ifdef TEST + *logofs << "setOpcodes: Propagated opcodes store to channel " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + return 1; +} + +int Channel::setStores(ClientStore *clientStore, ServerStore *serverStore) +{ + clientStore_ = clientStore; + serverStore_ = serverStore; + + #ifdef TEST + *logofs << "setStores: Propagated message stores to channel " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + return 1; +} + +int Channel::setCaches(ClientCache *clientCache, ServerCache *serverCache) +{ + clientCache_ = clientCache; + serverCache_ = serverCache; + + #ifdef TEST + *logofs << "setCaches: Propagated encode caches to channel " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + return 1; +} diff --git a/nxcomp/src/Channel.h b/nxcomp/src/Channel.h new file mode 100644 index 000000000..93b022630 --- /dev/null +++ b/nxcomp/src/Channel.h @@ -0,0 +1,664 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Channel_H +#define Channel_H + +#include "Transport.h" + +#include "WriteBuffer.h" + +#include "OpcodeStore.h" + +#include "ClientStore.h" +#include "ServerStore.h" + +#include "ClientCache.h" +#include "ServerCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Forward declaration of referenced classes. +// + +class List; + +class StaticCompressor; + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Define this to log a line when a channel +// is created or destroyed. +// + +#undef REFERENCES + +// +// Type of traffic carried by channel. +// + +typedef enum +{ + channel_none = -1, + channel_x11, + channel_cups, + channel_smb, + channel_media, + channel_http, + channel_font, + channel_slave, + channel_last_tag + +} T_channel_type; + +// +// Type of notification event to be sent +// by proxy to the X channel. +// + +typedef enum +{ + notify_no_split, + notify_start_split, + notify_commit_split, + notify_end_split, + notify_empty_split, + +} T_notification_type; + +class Channel +{ + public: + + // + // Maximum number of X connections supported. + // + + static const int CONNECTIONS_LIMIT = 256; + + Channel(Transport *transport, StaticCompressor *compressor); + + virtual ~Channel(); + + // + // Read any X message available on the X + // connection and encode it to the encode + // buffer. + // + + virtual int handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, + unsigned int length) = 0; + + // + // Decode any X message encoded in the + // proxy message and write it to the X + // connection. + // + + virtual int handleWrite(const unsigned char *message, unsigned int length) = 0; + + // + // Other methods to be implemented in + // client, server and generic channel + // classes. + // + + virtual int handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, + T_store_action action, int position, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) = 0; + + virtual int handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, + T_store_action action, int position, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) = 0; + + virtual int handleSplit(EncodeBuffer &encodeBuffer) = 0; + + virtual int handleSplit(DecodeBuffer &decodeBuffer) = 0; + + virtual int handleSplitEvent(EncodeBuffer &encodeBuffer, Split *split) = 0; + + virtual int handleSplitEvent(DecodeBuffer &decodeBuffer) = 0; + + virtual int handleMotion(EncodeBuffer &encodeBuffer) = 0; + + virtual int handleCompletion(EncodeBuffer &encodeBuffer) = 0; + + virtual int handleConfiguration() = 0; + + virtual int handleFinish() = 0; + + // + // Interleave reads of the available + // events while writing data to the + // channel socket. + // + + virtual int handleAsyncEvents() = 0; + + // + // Handle the channel tear down. + // + + int handleClosing() + { + closing_ = 1; + + return 1; + } + + int handleDrop() + { + drop_ = 1; + + return 1; + } + + // + // Try to read more data from the socket. In + // the meanwhile flush any enqueued data if + // the channel is blocked. Return as soon as + // more data has been read or the timeout has + // been exceeded. + // + + int handleWait(int timeout); + + // + // Drain the output buffer while handling the + // data that may become readable. + // + + int handleDrain(int timeout, int limit); + + // + // Flush any remaining data in the transport + // buffer. + // + + int handleFlush(); + + // + // Called when the loop has replaced or + // closed a previous alert. + // + + void handleResetAlert(); + + // + // Initialize all the static members. + // + + static int setReferences(); + + // + // Set pointer to object mapping opcodes + // of NX specific messages. + // + + int setOpcodes(OpcodeStore *opcodeStore); + + // + // Update pointers to message stores in + // channels. + // + + int setStores(ClientStore *clientStore, ServerStore *serverStore); + + // + // The same for channels caches. + // + + int setCaches(ClientCache *clientCache, ServerCache *serverCache); + + // + // Set the port used for tunneling of the + // font server connections. + // + + void setPorts(int fontPort) + { + fontPort_ = fontPort; + } + + // + // Check if there are pending split + // to send to the remote side. + // + + virtual int needSplit() const = 0; + + // + // Check if there are motion events + // to flush. + // + + virtual int needMotion() const = 0; + + // + // Return the type of traffic carried + // by this channel. + // + + virtual T_channel_type getType() const = 0; + + // + // Check if the channel has been marked + // as closing down. + // + + int getFinish() const + { + return finish_; + } + + int getClosing() + { + return closing_; + } + + int getDrop() + { + return drop_; + } + + int getCongestion() + { + return congestion_; + } + + protected: + + int handleFlush(T_flush type) + { + // + // We could write the data immediately if there + // is already something queued to the low level + // TCP buffers. + // + // if (... || transport_ -> queued() > 0) + // { + // ... + // } + // + + if (writeBuffer_.getScratchLength() > 0 || + (type == flush_if_any && writeBuffer_.getLength() > 0) || + writeBuffer_.getLength() >= (unsigned int) + control -> TransportFlushBufferSize) + { + return handleFlush(type, writeBuffer_.getLength(), + writeBuffer_.getScratchLength()); + } + + return 0; + } + + // + // Actually flush the data to the + // channel descriptor. + // + + int handleFlush(T_flush type, int bufferLength, int scratchLength); + + // + // Handle the congestion changes. + // + + int handleCongestion(); + + // + // Encode and decode X messages. + // + + int handleEncode(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, + MessageStore *store, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + int handleDecode(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, + MessageStore *store, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + // + // Encode the message based on its + // message store. + // + + int handleEncodeCached(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, + MessageStore *store, const unsigned char *buffer, + const unsigned int size); + + int handleDecodeCached(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, + MessageStore *store, unsigned char *&buffer, + unsigned int &size); + + int handleEncodeIdentity(EncodeBuffer &encodeBuffer, ChannelCache *channelCache, + MessageStore *store, const unsigned char *buffer, + const unsigned int size, int bigEndian) + { + return (store -> encodeIdentity(encodeBuffer, buffer, size, + bigEndian, channelCache)); + } + + int handleDecodeIdentity(DecodeBuffer &decodeBuffer, ChannelCache *channelCache, + MessageStore *store, unsigned char *&buffer, + unsigned int &size, int bigEndian, + WriteBuffer *writeBuffer) + { + return (store -> decodeIdentity(decodeBuffer, buffer, size, bigEndian, + writeBuffer, channelCache)); + } + + // + // Other utility functions used by + // the encoding and decoding methods. + // + + void handleCopy(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned int offset, const unsigned char *buffer, + const unsigned int size) + { + if (size > offset) + { + encodeBuffer.encodeMemory(buffer + offset, size - offset); + } + } + + void handleCopy(DecodeBuffer &decodeBuffer, const unsigned char opcode, + const unsigned int offset, unsigned char *buffer, + const unsigned int size) + { + if (size > offset) + { + memcpy(buffer + offset, decodeBuffer.decodeMemory(size - offset), size - offset); + } + } + + void handleUpdate(MessageStore *store, const unsigned int dataSize, + const unsigned int compressedDataSize) + { + if (store -> lastAction == IS_ADDED) + { + handleUpdateAdded(store, dataSize, compressedDataSize); + } + } + + void handleSave(MessageStore *store, unsigned char *buffer, unsigned int size, + const unsigned char *compressedData = NULL, + const unsigned int compressedDataSize = 0) + { + if (store -> lastAction == IS_ADDED) + { + handleSaveAdded(store, 0, buffer, size, compressedData, compressedDataSize); + } + } + + void handleSaveSplit(MessageStore *store, unsigned char *buffer, + unsigned int size) + { + if (store -> lastAction == IS_ADDED) + { + return handleSaveAdded(store, 1, buffer, size, 0, 0); + } + } + + void handleUpdateAdded(MessageStore *store, const unsigned int dataSize, + const unsigned int compressedDataSize); + + void handleSaveAdded(MessageStore *store, int split, unsigned char *buffer, + unsigned int size, const unsigned char *compressedData, + const unsigned int compressedDataSize); + + // + // Compress the data part of a message + // using ZLIB or another compressor + // and send it over the network. + // + + int handleCompress(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned int offset, const unsigned char *buffer, + const unsigned int size, unsigned char *&compressedData, + unsigned int &compressedDataSize); + + int handleDecompress(DecodeBuffer &decodeBuffer, const unsigned char opcode, + const unsigned int offset, unsigned char *buffer, + const unsigned int size, const unsigned char *&compressedData, + unsigned int &compressedDataSize); + + // + // Send an X_NoOperation to the X server. + // The second version also removes any + // previous data in the write buffer. + // + + int handleNullRequest(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size); + + int handleCleanAndNullRequest(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size); + + // + // X11 channels are considered to be in + // congestion state when there was a + // blocking write and, since then, the + // local end didn't consume all the data. + // + + virtual int isCongested() + { + return (transport_ -> getType() != + transport_agent && transport_ -> length() > + control -> TransportFlushBufferSize); + } + + virtual int isReliable() + { + return 1; + } + + // + // Determine how to handle allocation + // of new messages in the message + // stores. + // + + int mustCleanStore(MessageStore *store) + { + return (store -> getRemoteTotalStorageSize() > control -> + RemoteTotalStorageSize || store -> getLocalTotalStorageSize() > + control -> LocalTotalStorageSize || (store -> getRemoteStorageSize() > + (control -> RemoteTotalStorageSize / 100 * store -> + cacheThreshold)) || (store -> getLocalStorageSize() > + (control -> LocalTotalStorageSize / 100 * store -> + cacheThreshold))); + } + + int canCleanStore(MessageStore *store) + { + return ((store -> getSize() > 0 && (store -> getRemoteStorageSize() > + (control -> RemoteTotalStorageSize / 100 * store -> + cacheLowerThreshold))) || (store -> getLocalStorageSize() > + (control -> LocalTotalStorageSize / 100 * store -> + cacheLowerThreshold))); + } + + protected: + + // + // Set up the split stores. + // + + void handleSplitStoreError(int resource); + + void handleSplitStoreAlloc(List *list, int resource); + void handleSplitStoreRemove(List *list, int resource); + + Split *handleSplitCommitRemove(int request, int resource, int position); + + void validateSize(const char *name, int input, int output, + int offset, int size) + { + if (size < offset || size > control -> MaximumMessageSize || + size != (int) RoundUp4(input) + offset || + output > control -> MaximumMessageSize) + { + *logofs << "Channel: PANIC! Invalid size " << size + << " for " << name << " output with data " + << input << "/" << output << "/" << offset + << "/" << size << ".\n" << logofs_flush; + + cerr << "Error" << ": Invalid size " << size + << " for " << name << " output.\n"; + + HandleAbort(); + } + } + + // + // Is the X client big endian? + // + + int bigEndian() const + { + return bigEndian_; + } + + int bigEndian_; + + // + // Other X server's features + // saved at session startup. + // + + unsigned int imageByteOrder_; + unsigned int bitmapBitOrder_; + unsigned int scanlineUnit_; + unsigned int scanlinePad_; + + int firstRequest_; + int firstReply_; + + // + // Use this class for IO operations. + // + + Transport *transport_; + + // + // The static compressor is created by the + // proxy and shared among channels. + // + + StaticCompressor *compressor_; + + // + // Map NX operations to opcodes. Propagated + // by proxy to all channels on the same X + // server. + // + + OpcodeStore *opcodeStore_; + + // + // Also stores are shared between channels. + // + + ClientStore *clientStore_; + ServerStore *serverStore_; + + // + // Caches are specific for each channel. + // + + ClientCache *clientCache_; + ServerCache *serverCache_; + + // + // Data going to X connection. + // + + WriteBuffer writeBuffer_; + + // + // Other data members. + // + + int fd_; + + int finish_; + int closing_; + int drop_; + int congestion_; + int priority_; + + int alert_; + + // + // It will be set to the descriptor of the + // first X channel that is successfully con- + // nected and will print an info message on + // standard error. + // + + static int firstClient_; + + // + // Port used for font server connections. + // + + static int fontPort_; + + // + // Track which cache operations have been + // enabled by the agent. + // + + int enableCache_; + int enableSplit_; + int enableSave_; + int enableLoad_; + + // + // Keep track of object creation and + // deletion. + // + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +#endif /* Channel_H */ diff --git a/nxcomp/src/ChannelCache.cpp b/nxcomp/src/ChannelCache.cpp new file mode 100644 index 000000000..f30f18bc1 --- /dev/null +++ b/nxcomp/src/ChannelCache.cpp @@ -0,0 +1,68 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ChannelCache.h" + +const unsigned int CONFIGUREWINDOW_FIELD_WIDTH[7] = +{ + 16, // x + 16, // y + 16, // width + 16, // height + 16, // border width + 29, // sibling window + 3 // stack mode +}; + +const unsigned int CREATEGC_FIELD_WIDTH[23] = +{ + 4, // function + 32, // plane mask + 32, // foreground + 32, // background + 16, // line width + 2, // line style + 2, // cap style + 2, // join style + 2, // fill style + 1, // fill rule + 29, // tile + 29, // stipple + 16, // tile/stipple x origin + 16, // tile/stipple y origin + 29, // font + 1, // subwindow mode + 1, // graphics exposures + 16, // clip x origin + 16, // clip y origin + 29, // clip mask + 16, // card offset + 8, // dashes + 1 // arc mode +}; diff --git a/nxcomp/src/ChannelCache.h b/nxcomp/src/ChannelCache.h new file mode 100644 index 000000000..6a29c3847 --- /dev/null +++ b/nxcomp/src/ChannelCache.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ChannelCache_H +#define ChannelCache_H + +// +// Sizes of optional fields for ConfigureWindow +// request. +// + +extern const unsigned int CONFIGUREWINDOW_FIELD_WIDTH[7]; + +// +// Sizes of optional fields for CreateGC request. +// + +extern const unsigned int CREATEGC_FIELD_WIDTH[23]; + +// +// This is just needed to provide a pointer +// to the base cache class in encoding and +// decoding procedures of message stores. +// + +class ChannelCache +{ + public: + + ChannelCache() + { + } + + ~ChannelCache() + { + } +}; + +#endif /* ChannelCache_H */ diff --git a/nxcomp/src/ChannelEndPoint.cpp b/nxcomp/src/ChannelEndPoint.cpp new file mode 100644 index 000000000..921615bae --- /dev/null +++ b/nxcomp/src/ChannelEndPoint.cpp @@ -0,0 +1,349 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "ChannelEndPoint.h" + +#include "NXalert.h" + +ChannelEndPoint::ChannelEndPoint(const char *spec) + : defaultTCPPort_(0), defaultTCPInterface_(0), + defaultUnixPath_(NULL), spec_(NULL) { + setSpec(spec); +} + +ChannelEndPoint::~ChannelEndPoint() +{ + char *unixPath = NULL; + + if (getUnixPath(&unixPath)) + { + struct stat st; + lstat(unixPath, &st); + if(S_ISSOCK(st.st_mode)) + unlink(unixPath); + } +} + +void +ChannelEndPoint::setSpec(const char *spec) { + if (spec_) free(spec_); + + if (spec && strlen(spec)) + { + spec_ = strdup(spec); + isUnix_ = getUnixPath(); + isTCP_ = getTCPHostAndPort(); + } + else + { + spec_ = NULL; + isUnix_ = false; + isTCP_ = false; + } +} + +void +ChannelEndPoint::setSpec(long port) { + if (port >= 0) { + char tmp[20]; + sprintf(tmp, "%ld", port); + setSpec(tmp); + } + else { + disable(); + } +} + +void +ChannelEndPoint::setSpec(const char *hostName, long port) { + int length; + + if (spec_) free(spec_); + isUnix_ = false; + isTCP_ = false; + + if (hostName && strlen(hostName) && port >= 1) + { + length = snprintf(NULL, 0, "tcp:%s:%ld", hostName, port); + spec_ = (char *)calloc(length + 1, sizeof(char)); + snprintf(spec_, length+1, "tcp:%s:%ld", hostName, port); + isTCP_ = true; + } + else setSpec((char*)NULL); +} + +bool +ChannelEndPoint::getSpec(char **socketUri) const { + + if (socketUri) *socketUri = NULL; + + char *unixPath = NULL; + char *hostName = NULL; + long port = -1; + + char *newSocketUri = NULL; + int length = -1; + + if (getUnixPath(&unixPath)) + { + length = snprintf(NULL, 0, "unix:%s", unixPath); + } + else if (getTCPHostAndPort(&hostName, &port)) + { + length = snprintf(NULL, 0, "tcp:%s:%ld", hostName, port); + } + + if (length > 0) + { + newSocketUri = (char *)calloc(length + 1, sizeof(char)); + if (isUnixSocket()) + snprintf(newSocketUri, length+1, "unix:%s", unixPath); + else + snprintf(newSocketUri, length+1, "tcp:%s:%ld", hostName, port); + + if (socketUri) + *socketUri = strdup(newSocketUri); + } + + free(newSocketUri); + free(unixPath); + free(hostName); + + if (NULL != *socketUri) + return true; + + return false; +} + +void +ChannelEndPoint::setDefaultTCPPort(long port) { + defaultTCPPort_ = port; +} + +void +ChannelEndPoint::setDefaultTCPInterface(int publicInterface) { + defaultTCPInterface_ = publicInterface; +} + +void +ChannelEndPoint::setDefaultUnixPath(char *path) { + if (defaultUnixPath_) free(defaultUnixPath_); + + if (path && strlen(path)) + defaultUnixPath_ = strdup(path); + else + defaultUnixPath_ = NULL; +} + +void +ChannelEndPoint::disable() { + setSpec("0"); +} + +bool +ChannelEndPoint::getPort(long *port) const { + if (port) *port = 0; + long p = -1; + if (spec_) { + char *end; + p = strtol(spec_, &end, 10); + if ((end == spec_) || (*end != '\0')) + return false; + } + + if (port) *port = p; + return true; +} + +bool +ChannelEndPoint::getUnixPath(char **unixPath) const { + + if (unixPath) *unixPath = 0; + + long p; + char *path = NULL; + + if (getPort(&p)) { + if (p != 1) return false; + } + else if (spec_ && (strncmp("unix:", spec_, 5) == 0)) { + path = spec_ + 5; + } + else + return false; + + if (!path || (*path == '\0')) { + path = defaultUnixPath_; + if (!path) + return false; + } + + if (unixPath) + *unixPath = strdup(path); + + return true; +} + +bool +ChannelEndPoint::isUnixSocket() const { + return isUnix_; +} + +// FIXME!!! +static const char * +getComputerName() { + // + // Strangely enough, under some Windows OSes SMB + // service doesn't bind to localhost. Fall back + // to localhost if can't find computer name in + // the environment. In future we should try to + // bind to localhost and then try the other IPs. + // + + const char *hostname = NULL; + + #ifdef __CYGWIN32__ + + hostname = getenv("COMPUTERNAME"); + + #endif + + if (hostname == NULL) + { + hostname = "localhost"; + } + + return hostname; +} + +bool +ChannelEndPoint::getTCPHostAndPort(char **host, long *port) const { + long p; + char *h = NULL; + ssize_t h_len; + + if (host) *host = NULL; + if (port) *port = 0; + + if (getPort(&p)) { + h_len = 0; + } + else if (spec_ && (strncmp("tcp:", spec_, 4) == 0)) { + h = spec_ + 4; + char *colon = strrchr(h, ':'); + if (colon) { + char *end; + h_len = colon++ - h; + p = strtol(colon, &end, 10); + if ((end == colon) || (*end != '\0')) + return false; + } + else { + h_len = strlen(h); + p = 1; + } + } + else + return false; + + if (p == 1) p = defaultTCPPort_; + if (p < 1) return false; + + if (port) + *port = p; + + if (host) + *host = ( h_len + ? strndup(h, h_len) + : strdup(defaultTCPInterface_ ? getComputerName() : "localhost")); + + return true; +} + +bool +ChannelEndPoint::isTCPSocket() const { + return isTCP_; +} + +long ChannelEndPoint::getTCPPort() const { + long port; + if (getTCPHostAndPort(NULL, &port)) return port; + return -1; +} + +bool +ChannelEndPoint::enabled() const { + return (isUnixSocket() || isTCPSocket()); +} + +bool +ChannelEndPoint::validateSpec() { + isTCP_ = getTCPHostAndPort(); + isUnix_ = getUnixPath(); + return ( getPort() || isUnix_ || isTCP_ ); +} + +ChannelEndPoint &ChannelEndPoint::operator=(const ChannelEndPoint &other) { + char *old; + defaultTCPPort_ = other.defaultTCPPort_; + defaultTCPInterface_ = other.defaultTCPInterface_; + old = defaultUnixPath_; + defaultUnixPath_ = (other.defaultUnixPath_ ? strdup(other.defaultUnixPath_) : NULL); + free(old); + old = spec_; + spec_ = (other.spec_ ? strdup(other.spec_) : NULL); + free(old); + isUnix_ = getUnixPath(); + isTCP_ = getTCPHostAndPort(); + return *this; +} + +std::ostream& operator<<(std::ostream& os, const ChannelEndPoint& endPoint) { + if (endPoint.enabled()) { + char* endPointSpec = NULL; + if (endPoint.getSpec(&endPointSpec)) + { + os << endPointSpec; + free(endPointSpec); + } + else + os << "(invalid)"; + } + else + { + os << "(disabled)"; + } + return os; +} diff --git a/nxcomp/src/ChannelEndPoint.h b/nxcomp/src/ChannelEndPoint.h new file mode 100644 index 000000000..4c0c728f3 --- /dev/null +++ b/nxcomp/src/ChannelEndPoint.h @@ -0,0 +1,71 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ChannelEndPoint_H +#define ChannelEndPoint_H + +#include +#include + +class ChannelEndPoint +{ + private: + long defaultTCPPort_; + int defaultTCPInterface_; // 0=localhost, otherwise IP of public interface. + char *defaultUnixPath_; + char *spec_; + bool isUnix_; + bool isTCP_; + + bool getPort(long *port = NULL) const; + + public: + ChannelEndPoint(const char *spec = NULL); + ~ChannelEndPoint(); + ChannelEndPoint &operator=(const ChannelEndPoint &other); + + bool enabled() const; + bool disabled() { return !enabled(); } + void disable(); + void setSpec(const char *spec); + void setSpec(long port); + void setSpec(const char *hostName, long port); + bool getSpec(char **socketUri) const; + void setDefaultTCPPort(long port); + void setDefaultTCPInterface(int publicInterface); + void setDefaultUnixPath(char *path); + + bool getUnixPath(char **path = NULL) const; + bool isUnixSocket() const; + bool getTCPHostAndPort(char **hostname = NULL, long *port = NULL) const; + long getTCPPort() const; + bool isTCPSocket() const; + + bool validateSpec(); +}; + +std::ostream& operator<<(std::ostream& os, const ChannelEndPoint& endPoint); + +#endif diff --git a/nxcomp/src/ChannelStore.h b/nxcomp/src/ChannelStore.h new file mode 100644 index 000000000..53bb60f73 --- /dev/null +++ b/nxcomp/src/ChannelStore.h @@ -0,0 +1,54 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ChannelStore_H +#define ChannelStore_H + +// +// One message store for each opcode. +// + +#define CHANNEL_STORE_OPCODE_LIMIT 256 + +// +// One split store for each resource. +// + +#define CHANNEL_STORE_RESOURCE_LIMIT 256 + +class ChannelStore +{ + public: + + ChannelStore() + { + } + + virtual ~ChannelStore() + { + } +}; + +#endif /* ChannelStore_H */ diff --git a/nxcomp/src/CharCache.cpp b/nxcomp/src/CharCache.cpp new file mode 100644 index 000000000..ed0e5a02a --- /dev/null +++ b/nxcomp/src/CharCache.cpp @@ -0,0 +1,73 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "CharCache.h" + +int CharCache::lookup(unsigned char value, unsigned int &index) +{ + for (unsigned int i = 0; i < length_; i++) + if (value == buffer_[i]) + { + index = i; + if (i) + { + unsigned int target = (i >> 1); + do + { + buffer_[i] = buffer_[i - 1]; + i--; + } + while (i > target); + buffer_[target] = value; + } + return 1; + } + insert(value); + return 0; +} + +void CharCache::insert(unsigned char value) +{ + unsigned int insertionPoint = 0; + if (2 >= length_) + insertionPoint = length_; + else + insertionPoint = 2; + unsigned int start; + if (length_ >= 7) + start = 7 - 1; + else + { + start = length_; + length_++; + } + for (unsigned int k = start; k > insertionPoint; k--) + buffer_[k] = buffer_[k - 1]; + buffer_[insertionPoint] = value; +} diff --git a/nxcomp/src/CharCache.h b/nxcomp/src/CharCache.h new file mode 100644 index 000000000..b8891d2df --- /dev/null +++ b/nxcomp/src/CharCache.h @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef CharCache_H +#define CharCache_H + +// +// CharCache is a counterpart of IntCache that is +// optimized for use in compressing text composed +// of 8-bit characters. +// + +class CharCache +{ + public: + + CharCache() : length_(0) + { + } + + ~CharCache() + { + } + + unsigned int getSize() const + { + return (unsigned int) length_; + } + + int lookup(unsigned char value, unsigned int &index); + + // + // This can be inlined as it is only + // called by decodeCachedValue(). + // + + unsigned int get(unsigned int index) + { + unsigned char result = buffer_[index]; + + if (index != 0) + { + unsigned int i = index; + unsigned int target = (i >> 1); + + do + { + buffer_[i] = buffer_[i - 1]; + + i--; + } + while (i > target); + + buffer_[target] = result; + } + + return (unsigned int) result; + } + + void insert(unsigned char value); + + private: + + unsigned char length_; + + unsigned char buffer_[7]; +}; + +#endif /* CharCache_H */ diff --git a/nxcomp/src/Children.cpp b/nxcomp/src/Children.cpp new file mode 100644 index 000000000..49ab13352 --- /dev/null +++ b/nxcomp/src/Children.cpp @@ -0,0 +1,1059 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "NX.h" + +#include "Misc.h" + +#include "Types.h" +#include "Timestamp.h" + +#include "Control.h" +#include "Statistics.h" +#include "Proxy.h" + +#include "Keeper.h" +#include "Fork.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define DISPLAY_LENGTH_LIMIT 256 +#define DEFAULT_STRING_LIMIT 512 + +// +// These are from the main loop. +// + +extern Keeper *keeper; + +extern int (*handler)(int); + +extern int useUnixSocket; + +extern int lastDialog; +extern int lastWatchdog; +extern int lastKeeper; + +extern void CleanupListeners(); +extern void CleanupSockets(); +extern void CleanupAgent(); +extern void CleanupGlobal(); + +extern void InstallSignals(); + +extern char *GetClientPath(); + +extern int CheckParent(const char *name, const char *type, + int parent); + +#ifdef __sun +extern char **environ; +#endif + +// +// Close all the unused descriptors and +// install any signal handler that might +// have been disabled in the main process. +// + +static void SystemCleanup(const char *name); + +// +// Release all objects allocated in the +// heap. + +static void MemoryCleanup(const char *name); + +// +// Remove 'name' from the environment. +// + +static int UnsetEnv(const char *name); + +static int NXTransKeeperHandler(int signal); +static void NXTransKeeperCheck(); + + +// +// Start a nxclient process in dialog mode. +// + +int NXTransDialog(const char *caption, const char *message, + const char *window, const char *type, int local, + const char* display) +{ + // + // Be sure log file is valid. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + int pid; + + #ifdef TEST + *logofs << "NXTransDialog: Going to fork with NX pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + pid = Fork(); + + if (pid != 0) + { + if (pid < 0) + { + #ifdef TEST + *logofs << "NXTransDialog: WARNING! Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + } + #ifdef TEST + else + { + *logofs << "NXTransDialog: Created NX dialog process " + << "with pid '" << pid << "'.\n" + << logofs_flush; + } + #endif + + return pid; + } + + #ifdef TEST + *logofs << "NXTransDialog: Executing child with pid '" + << getpid() << "' and parent '" << getppid() + << "'.\n" << logofs_flush; + #endif + + SystemCleanup("NXTransDialog"); + + // + // Copy the client command before + // freeing up the control class. + // + + char command[DEFAULT_STRING_LIMIT]; + + if (control != NULL) + { + strcpy(command, control -> ClientPath); + } + else + { + char *path = GetClientPath(); + + strcpy(command, path); + + delete [] path; + } + + // + // Get rid of the unused resources. + // + + MemoryCleanup("NXTransDialog"); + + #ifdef TEST + *logofs << "NXTransDialog: Running external NX dialog with caption '" + << caption << "' message '" << message << "' type '" + << type << "' local '" << local << "' display '" + << display << "'.\n" + << logofs_flush; + #endif + + int pulldown = (strcmp(type, "pulldown") == 0); + + char parent[DEFAULT_STRING_LIMIT]; + + snprintf(parent, DEFAULT_STRING_LIMIT, "%d", getppid()); + + parent[DEFAULT_STRING_LIMIT - 1] = '\0'; + + UnsetEnv("LD_LIBRARY_PATH"); + + for (int i = 0; i < 2; i++) + { + if (local != 0) + { + if (pulldown) + { + execlp(command, command, "--dialog", type, "--caption", caption, + "--window", window, "--local", "--parent", parent, + "--display", display, NULL); + } + else + { + execlp(command, command, "--dialog", type, "--caption", caption, + "--message", message, "--local", "--parent", parent, + "--display", display, NULL); + } + } + else + { + if (pulldown) + { + execlp(command, command, "--dialog", type, "--caption", caption, + "--window", window, "--parent", parent, + "--display", display, NULL); + } + else + { + execlp(command, command, "--dialog", type, "--caption", caption, + "--message", message, "--parent", parent, + "--display", display, NULL); + } + } + + #ifdef WARNING + *logofs << "NXTransDialog: WARNING! Couldn't start '" + << command << "'. " << "Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Couldn't start '" << command + << "'. Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + // + // Retry by looking for the default name + // in the default NX path. + // + + if (i == 0) + { + + strcpy(command, "nxclient"); + + char newPath[DEFAULT_STRING_LIMIT]; + + strcpy(newPath, "/usr/NX/bin:/opt/NX/bin:/usr/local/NX/bin:"); + + #ifdef __APPLE__ + + strcat(newPath, "/Applications/NX Client for OSX.app/Contents/MacOS:"); + + #endif + + #ifdef __CYGWIN32__ + + strcat(newPath, ".:"); + + #endif + + int newLength = strlen(newPath); + + char *oldPath = getenv("PATH"); + + strncpy(newPath + newLength, oldPath, DEFAULT_STRING_LIMIT - newLength - 1); + + newPath[DEFAULT_STRING_LIMIT - 1] = '\0'; + + #ifdef WARNING + *logofs << "NXTransDialog: WARNING! Trying with path '" + << newPath << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Trying with path '" << newPath + << "'.\n"; + + // + // Solaris doesn't seem to have + // function setenv(). + // + + #ifdef __sun + + char newEnv[DEFAULT_STRING_LIMIT + 5]; + + sprintf(newEnv,"PATH=%s", newPath); + + putenv(newEnv); + + #else + + setenv("PATH", newPath, 1); + + #endif + + } + } + + // + // Hopefully useless. + // + + exit(0); +} + +// +// Start a nxclient process in dialog mode. +// + +int NXTransClient(const char* display) +{ + // + // Be sure log file is valid. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + int pid; + + #ifdef TEST + *logofs << "NXTransClient: Going to fork with NX pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + pid = Fork(); + + if (pid != 0) + { + if (pid < 0) + { + #ifdef TEST + *logofs << "NXTransClient: WARNING! Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + } + #ifdef TEST + else + { + *logofs << "NXTransClient: Created NX client process " + << "with pid '" << pid << "'.\n" + << logofs_flush; + } + #endif + + return pid; + } + + #ifdef TEST + *logofs << "NXTransClient: Executing child with pid '" + << getpid() << "' and parent '" << getppid() + << "'.\n" << logofs_flush; + #endif + + SystemCleanup("NXTransClient"); + + // + // Copy the client command before + // freeing up the control class. + // + + char command[DEFAULT_STRING_LIMIT]; + + if (control != NULL) + { + strcpy(command, control -> ClientPath); + } + else + { + char *path = GetClientPath(); + + strcpy(command, path); + + delete [] path; + } + + // + // Get rid of unused resources. + // + + MemoryCleanup("NXTransClient"); + + #ifdef TEST + *logofs << "NXTransClient: Running external NX client with display '" + << display << "'.\n" << logofs_flush; + #endif + + // + // Provide the display in the environment. + // + + char newDisplay[DISPLAY_LENGTH_LIMIT]; + + #ifdef __sun + + snprintf(newDisplay, DISPLAY_LENGTH_LIMIT - 1, "DISPLAY=%s", display); + + newDisplay[DISPLAY_LENGTH_LIMIT - 1] = '\0'; + + putenv(newDisplay); + + #else + + strncpy(newDisplay, display, DISPLAY_LENGTH_LIMIT - 1); + + newDisplay[DISPLAY_LENGTH_LIMIT - 1] = '\0'; + + setenv("DISPLAY", newDisplay, 1); + + #endif + + UnsetEnv("LD_LIBRARY_PATH"); + + for (int i = 0; i < 2; i++) + { + execlp(command, command, NULL); + + #ifdef WARNING + *logofs << "NXTransClient: WARNING! Couldn't start '" + << command << "'. Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Couldn't start '" << command + << "'. Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + // + // Retry by looking for the default name + // in the default NX path. + // + + if (i == 0) + { + + strcpy(command, "nxclient"); + + char newPath[DEFAULT_STRING_LIMIT]; + + strcpy(newPath, "/usr/NX/bin:/opt/NX/bin:/usr/local/NX/bin:"); + + #ifdef __APPLE__ + + strcat(newPath, "/Applications/NX Client for OSX.app/Contents/MacOS:"); + + #endif + + #ifdef __CYGWIN32__ + + strcat(newPath, ".:"); + + #endif + + int newLength = strlen(newPath); + + char *oldPath = getenv("PATH"); + + strncpy(newPath + newLength, oldPath, DEFAULT_STRING_LIMIT - newLength - 1); + + newPath[DEFAULT_STRING_LIMIT - 1] = '\0'; + + #ifdef WARNING + *logofs << "NXTransClient: WARNING! Trying with path '" + << newPath << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Trying with path '" << newPath + << "'.\n"; + + // + // Solaris doesn't seem to have + // function setenv(). + // + + #ifdef __sun + + char newEnv[DEFAULT_STRING_LIMIT + 5]; + + sprintf(newEnv,"PATH=%s", newPath); + + putenv(newEnv); + + #else + + setenv("PATH", newPath, 1); + + #endif + } + + } + // + // Hopefully useless. + // + + exit(0); +} + +// +// Wait until the timeout is expired. +// The timeout is expressed in milli- +// seconds. +// + +int NXTransWatchdog(int timeout) +{ + // + // Be sure log file is valid. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + int pid; + + #ifdef TEST + *logofs << "NXTransWatchdog: Going to fork with NX pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + pid = Fork(); + + if (pid != 0) + { + if (pid < 0) + { + #ifdef TEST + *logofs << "NXTransWatchdog: WARNING! Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + } + #ifdef TEST + else + { + *logofs << "NXTransWatchdog: Created NX watchdog process " + << "with pid '" << pid << "'.\n" << logofs_flush; + } + #endif + + return pid; + } + + int parent = getppid(); + + #ifdef TEST + *logofs << "NXTransWatchdog: Executing child with pid '" + << getpid() << "' and parent '" << parent + << "'.\n" << logofs_flush; + #endif + + SystemCleanup("NXTransWatchdog"); + + // + // Get rid of unused resources. + // + + MemoryCleanup("NXTransWatchdog"); + + // + // Run until the timeout is expired + // or forever, if no timeout is + // provided. + // + + T_timestamp startTs = getTimestamp(); + + int diffTs = 0; + + for (;;) + { + // + // Complain if the parent is dead. + // + + if (CheckParent("NXTransWatchdog", "watchdog", parent) == 0) + { + #ifdef TEST + *logofs << "NXTransWatchdog: Exiting with no parent " + << "running.\n" << logofs_flush; + #endif + + HandleCleanup(); + } + + if (timeout > 0) + { + if (diffTs >= timeout) + { + #ifdef TEST + *logofs << "NXTransWatchdog: Timeout of " << timeout + << " Ms raised in watchdog.\n" << logofs_flush; + #endif + + // + // We will just exit. Our parent should be + // monitoring us and detect that the process + // is gone. + // + + HandleCleanup(); + } + } + + if (timeout > 0) + { + #ifdef TEST + *logofs << "NXTransWatchdog: Waiting for the timeout " + << "with " << timeout - diffTs << " Ms to run.\n" + << logofs_flush; + #endif + + usleep((timeout - diffTs) * 1000); + + diffTs = diffTimestamp(startTs, getNewTimestamp()); + } + else + { + #ifdef TEST + *logofs << "NXTransWatchdog: Waiting for a signal.\n" + << logofs_flush; + #endif + + sleep(10); + } + } + + // + // Hopefully useless. + // + + exit(0); +} + +int NXTransKeeperHandler(int signal) +{ + if (keeper != NULL) + { + switch (signal) + { + case SIGTERM: + case SIGINT: + case SIGHUP: + { + #ifdef TEST + *logofs << "NXTransKeeperHandler: Requesting giveup " + << "because of signal " << signal << " ,'" + << DumpSignal(signal) << "'.\n" + << logofs_flush; + #endif + + keeper -> setSignal(signal); + + return 0; + } + } + } + + return 1; +} + +void NXTransKeeperCheck() +{ + if (CheckParent("NXTransKeeper", "keeper", + keeper -> getParent()) == 0 || keeper -> getSignal() != 0) + { + #ifdef TEST + *logofs << "NXTransKeeperCheck: Exiting because of signal " + << "or no parent running.\n" << logofs_flush; + #endif + + HandleCleanup(); + } +} + +int NXTransKeeper(int caches, int images, const char *root) +{ + // + // Be sure log file is valid. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + if (caches == 0 && images == 0) + { + #ifdef TEST + *logofs << "NXTransKeeper: No NX cache house-keeping needed.\n" + << logofs_flush; + #endif + + return 0; + } + + int pid; + + #ifdef TEST + *logofs << "NXTransKeeper: Going to fork with NX pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + pid = Fork(); + + if (pid != 0) + { + if (pid < 0) + { + #ifdef TEST + *logofs << "NXTransKeeper: WARNING! Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + } + #ifdef TEST + else + { + *logofs << "NXTransKeeper: Created NX keeper process " + << "with pid '" << pid << "'.\n" + << logofs_flush; + } + #endif + + return pid; + } + + int parent = getppid(); + + #ifdef TEST + *logofs << "NXTransKeeper: Executing child with pid '" + << getpid() << "' and parent '" << parent + << "'.\n" << logofs_flush; + #endif + + SystemCleanup("NXTransKeeper"); + + #ifdef TEST + *logofs << "NXTransKeeper: Going to run with caches " << caches + << " images " << images << " and root " << root + << " at " << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + // + // Create the house-keeper class. + // + + int timeout = control -> KeeperTimeout; + + keeper = new Keeper(caches, images, root, 100, parent); + + handler = NXTransKeeperHandler; + + if (keeper == NULL) + { + #ifdef PANIC + *logofs << "NXTransKeeper: PANIC! Failed to create the keeper object.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed to create the keeper object.\n"; + + HandleCleanup(); + } + + // + // Get rid of unused resources. Root path + // must be copied in keeper's constructor + // before control is deleted. + // + + MemoryCleanup("NXTransKeeper"); + + // + // Decrease the priority of this process. + // + // The following applies to Cygwin: "Cygwin processes can be + // set to IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, HIGH_- + // PRIORITY_CLASS, or REALTIME_PRIORITY_CLASS with the nice + // call. If you pass a positive number to nice(), then the + // priority level will decrease by one (within the above list + // of priorities). A negative number would make it increase + // by one. It is not possible to change it by more than one + // at a time without making repeated calls". + // + + if (nice(5) < 0 && errno != 0) + { + #ifdef WARNING + *logofs << "NXTransKeeper: WARNING! Failed to renice process to +5. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Failed to renice process to +5. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + } + + // + // Delay a bit the first run to give + // a boost to the session startup. + // + + #ifdef TEST + *logofs << "NXTransKeeper: Going to sleep for " + << timeout / 20 << " Ms.\n" << logofs_flush; + #endif + + usleep(timeout / 20 * 1000); + + NXTransKeeperCheck(); + + // + // The house keeping of the persistent + // caches is performed only once. + // + + if (caches != 0) + { + #ifdef TEST + *logofs << "NXTransKeeper: Going to cleanup the NX cache " + << "directories at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + keeper -> cleanupCaches(); + + #ifdef TEST + *logofs << "NXTransKeeper: Completed cleanup of NX cache " + << "directories at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + } + #ifdef TEST + else + { + *logofs << "NXTransKeeper: Nothing to do for the " + << "persistent caches.\n" << logofs_flush; + } + #endif + + if (images == 0) + { + #ifdef TEST + *logofs << "NXTransKeeper: Nothing to do for the " + << "persistent images.\n" << logofs_flush; + #endif + + HandleCleanup(); + } + + // + // Take care of the persisten image cache. + // Run a number of iterations and then exit, + // so we can keep the memory consumption + // low. The parent will check our exit code + // and will eventually restart us. + // + + for (int iterations = 0; iterations < 100; iterations++) + { + #ifdef TEST + *logofs << "NXTransKeeper: Running iteration " << iterations + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + NXTransKeeperCheck(); + + #ifdef TEST + *logofs << "NXTransKeeper: Going to cleanup the NX images " + << "directories at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + if (keeper -> cleanupImages() < 0) + { + #ifdef TEST + *logofs << "NXTransKeeper: Exiting because of error " + << "handling the image cache.\n" << logofs_flush; + #endif + + HandleCleanup(); + } + + #ifdef TEST + *logofs << "NXTransKeeper: Completed cleanup of NX images " + << "directories at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + NXTransKeeperCheck(); + + #ifdef TEST + *logofs << "NXTransKeeper: Going to sleep for " << timeout + << " Ms.\n" << logofs_flush; + #endif + + usleep(timeout * 1000); + } + + HandleCleanup(2); + + // + // Hopefully useless. + // + + exit(0); +} + +void SystemCleanup(const char *name) +{ + #ifdef TEST + *logofs << name << ": Performing system cleanup in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + // + // Reinstall signals that might + // have been restored by agents. + // + + InstallSignals(); +} + +void MemoryCleanup(const char *name) +{ + #ifdef TEST + *logofs << name << ": Performing memory cleanup in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + DisableSignals(); + + // + // Prevent deletion of unix socket + // and lock file. + // + + useUnixSocket = 0; + + // + // Don't let cleanup kill other + // children. + // + + lastDialog = 0; + lastWatchdog = 0; + lastKeeper = 0; + + CleanupListeners(); + + CleanupSockets(); + + CleanupGlobal(); + + EnableSignals(); +} + +int UnsetEnv(const char *name) +{ + int result; + + #ifdef __sun + + char **pEnv = environ; + + int nameLen = strlen(name) + 1; + + char *varName = new char[nameLen + 1]; + + strcpy(varName, name); + + strcat(varName, "="); + + pEnv = environ; + + while (*pEnv != NULL) + { + if (!strncmp(varName, *pEnv, nameLen)) + { + break; + } + + *pEnv++; + } + + while (*pEnv != NULL) + { + *pEnv = *(pEnv + 1); + + pEnv++; + } + + result = 0; + + #else + + #ifdef __APPLE__ + + unsetenv(name); + result = 0; + + #else + + result = unsetenv(name); + + #endif + + #endif + + return result; +} diff --git a/nxcomp/src/ClearArea.cpp b/nxcomp/src/ClearArea.cpp new file mode 100644 index 000000000..0cb152d95 --- /dev/null +++ b/nxcomp/src/ClearArea.cpp @@ -0,0 +1,125 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ClearArea.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int ClearAreaStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ClearAreaMessage *clearArea = (ClearAreaMessage *) message; + + // + // Here is the fingerprint. + // + + clearArea -> exposures = *(buffer + 1); + + clearArea -> window = GetULONG(buffer + 4, bigEndian); + + clearArea -> x = GetUINT(buffer + 8, bigEndian); + clearArea -> y = GetUINT(buffer + 10, bigEndian); + clearArea -> width = GetUINT(buffer + 12, bigEndian); + clearArea -> height = GetUINT(buffer + 14, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int ClearAreaStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ClearAreaMessage *clearArea = (ClearAreaMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = clearArea -> exposures; + + PutULONG(clearArea -> window, buffer + 4, bigEndian); + + PutUINT(clearArea -> x, buffer + 8, bigEndian); + PutUINT(clearArea -> y, buffer + 10, bigEndian); + PutUINT(clearArea -> width, buffer + 12, bigEndian); + PutUINT(clearArea -> height, buffer + 14, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void ClearAreaStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + ClearAreaMessage *clearArea = (ClearAreaMessage *) message; + + *logofs << name() << ": Identity exposures " << (unsigned int) clearArea -> exposures + << ", window " << clearArea -> window << ", x " << clearArea -> x + << ", y " << clearArea -> y << ", width " << clearArea -> width + << ", height " << clearArea -> height << ", size " << clearArea -> size_ + << ".\n"; + + #endif +} + +void ClearAreaStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 1, 1); + md5_append(md5_state_, buffer + 4, 4); + md5_append(md5_state_, buffer + 8, 2); + md5_append(md5_state_, buffer + 10, 2); + md5_append(md5_state_, buffer + 12, 2); + md5_append(md5_state_, buffer + 14, 2); +} diff --git a/nxcomp/src/ClearArea.h b/nxcomp/src/ClearArea.h new file mode 100644 index 000000000..8067edffd --- /dev/null +++ b/nxcomp/src/ClearArea.h @@ -0,0 +1,182 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ClearArea_H +#define ClearArea_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define CLEARAREA_ENABLE_CACHE 1 +#define CLEARAREA_ENABLE_DATA 0 +#define CLEARAREA_ENABLE_SPLIT 0 +#define CLEARAREA_ENABLE_COMPRESS 0 + +#define CLEARAREA_DATA_LIMIT 0 +#define CLEARAREA_DATA_OFFSET 16 + +#define CLEARAREA_CACHE_SLOTS 3000 +#define CLEARAREA_CACHE_THRESHOLD 5 +#define CLEARAREA_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class ClearAreaMessage : public Message +{ + friend class ClearAreaStore; + + public: + + ClearAreaMessage() + { + } + + ~ClearAreaMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char exposures; + unsigned int window; + unsigned short x; + unsigned short y; + unsigned short width; + unsigned short height; +}; + +class ClearAreaStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + ClearAreaStore() : MessageStore() + { + enableCache = CLEARAREA_ENABLE_CACHE; + enableData = CLEARAREA_ENABLE_DATA; + enableSplit = CLEARAREA_ENABLE_SPLIT; + enableCompress = CLEARAREA_ENABLE_COMPRESS; + + dataLimit = CLEARAREA_DATA_LIMIT; + dataOffset = CLEARAREA_DATA_OFFSET; + + cacheSlots = CLEARAREA_CACHE_SLOTS; + cacheThreshold = CLEARAREA_CACHE_THRESHOLD; + cacheLowerThreshold = CLEARAREA_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~ClearAreaStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "ClearArea"; + } + + virtual unsigned char opcode() const + { + return X_ClearArea; + } + + virtual unsigned int storage() const + { + return sizeof(ClearAreaMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new ClearAreaMessage(); + } + + virtual Message *create(const Message &message) const + { + return new ClearAreaMessage((const ClearAreaMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (ClearAreaMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* ClearArea_H */ diff --git a/nxcomp/src/ClientCache.cpp b/nxcomp/src/ClientCache.cpp new file mode 100644 index 000000000..47bb7db1d --- /dev/null +++ b/nxcomp/src/ClientCache.cpp @@ -0,0 +1,392 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ClientCache.h" + +ClientCache::ClientCache() : + + freeGCCache(16), freeDrawableCache(16), freeWindowCache(16), + + cursorCache(16), colormapCache(16), visualCache(16), lastFont(0), + + changePropertyPropertyCache(16), changePropertyTypeCache(16), + changePropertyData32Cache(16), + + configureWindowBitmaskCache(4), + + convertSelectionRequestorCache(16), + convertSelectionLastTimestamp(0), + + copyPlaneBitPlaneCache(8), + + createGCBitmaskCache(8), + + createPixmapIdCache(16), createPixmapLastId(0), + createPixmapXCache(8), createPixmapYCache(8), + + createWindowBitmaskCache(8), + + fillPolyNumPointsCache(8), fillPolyIndex(0), + + getSelectionOwnerSelectionCache(8), + + grabButtonEventMaskCache(8), grabButtonConfineCache(8), + grabButtonModifierCache(8), + + grabKeyboardLastTimestamp(0), + + imageTextLengthCache(8), + imageTextLastX(0), imageTextLastY(0), + imageTextCacheX(8), imageTextCacheY(8), + + polySegmentCacheX(8), polySegmentCacheY(8), polySegmentCacheIndex(0), + + polyTextLastX(0), polyTextLastY(0), polyTextCacheX(8), + polyTextCacheY(8), polyTextFontCache(8), + + putImageWidthCache(8), putImageHeightCache(8), putImageLastX(0), + putImageLastY(0), putImageXCache(8), putImageYCache(8), + + getImagePlaneMaskCache(8), + + queryColorsLastPixel(0), + + setClipRectanglesXCache(8), setClipRectanglesYCache(8), + + setDashesLengthCache(8), setDashesOffsetCache(8), + + setSelectionOwnerCache(8), setSelectionOwnerTimestampCache(8), + + translateCoordsSrcCache(8), translateCoordsDstCache(8), + translateCoordsXCache(8), translateCoordsYCache(8), + + sendEventMaskCache(16), sendEventLastSequence(0), + sendEventIntDataCache(16), + + putPackedImageSrcLengthCache(16), putPackedImageDstLengthCache(16), + + // + // RenderExtension requests. + // + + renderFreePictureCache(16), + + renderGlyphSetCache(16), + renderFreeGlyphSetCache(16), + + renderIdCache(8), + + renderLengthCache(16), renderFormatCache(16), + renderValueMaskCache(8), renderNumGlyphsCache(8), + + renderXCache(16), renderYCache(16), + renderLastX(0), renderLastY(0), + + renderWidthCache(16), renderHeightCache(16), + + renderLastId(0), + + renderGlyphXCache(16), renderGlyphYCache(16), + renderGlyphX(0), renderGlyphY(0), + + renderLastCompositeGlyphsData(0), + + setCacheParametersCache(8), + + lastIdCache(16), lastId(0) + +{ + unsigned int i; + + for (i = 0; i < 3; i++) + { + allocColorRGBCache[i] = new IntCache(8); + + convertSelectionAtomCache[i] = new IntCache(8); + } + + for (i = 0; i < 4; i++) + { + clearAreaGeomCache[i] = new IntCache(8); + } + + for (i = 0; i < 7; i++) + { + configureWindowAttrCache[i] = new IntCache(8); + } + + for (i = 0; i < 6; i++) + { + copyAreaGeomCache[i] = new IntCache(8); + copyPlaneGeomCache[i] = new IntCache(8); + } + + for (i = 0; i < 23; i++) + { + if (CREATEGC_FIELD_WIDTH[i] > 16) + { + createGCAttrCache[i] = new IntCache(16); + } + else + { + createGCAttrCache[i] = new IntCache(CREATEGC_FIELD_WIDTH[i]); + } + } + + for (i = 0; i < 6; i++) + { + createWindowGeomCache[i] = new IntCache(8); + } + + for (i = 0; i < 15; i++) + { + createWindowAttrCache[i] = new IntCache(8); + } + + for (i = 0; i < 10; i++) + { + fillPolyXRelCache[i] = new IntCache(8); + fillPolyXAbsCache[i] = new IntCache(8); + fillPolyYRelCache[i] = new IntCache(8); + fillPolyYAbsCache[i] = new IntCache(8); + } + + for (i = 0; i < 8; i++) + { + fillPolyRecentX[i] = 0; + fillPolyRecentY[i] = 0; + } + + for (i = 0; i < 4; i++) + { + polyFillRectangleCacheX[i] = new IntCache(8); + polyFillRectangleCacheY[i] = new IntCache(8); + polyFillRectangleCacheWidth[i] = new IntCache(8); + polyFillRectangleCacheHeight[i] = new IntCache(8); + } + + for (i = 0; i < 2; i++) + { + polyLineCacheX[i] = new IntCache(8); + polyLineCacheY[i] = new IntCache(8); + } + + for (i = 0; i < 2; i++) + { + polyPointCacheX[i] = new IntCache(8); + polyPointCacheY[i] = new IntCache(8); + } + + for (i = 0; i < 4; i++) + { + polyRectangleGeomCache[i] = new IntCache(8); + } + + for (i = 0; i < 2; i++) + { + polySegmentLastX[i] = 0; + polySegmentLastY[i] = 0; + } + + for (i = 0; i < 4; i++) + { + setClipRectanglesGeomCache[i] = new IntCache(8); + } + + for (i = 0; i < 2; i++) + { + polyFillArcCacheX[i] = new IntCache(8); + polyFillArcCacheY[i] = new IntCache(8); + polyFillArcCacheWidth[i] = new IntCache(8); + polyFillArcCacheHeight[i] = new IntCache(8); + polyFillArcCacheAngle1[i] = new IntCache(8); + polyFillArcCacheAngle2[i] = new IntCache(8); + } + + for (i = 0; i < 2; i++) + { + polyArcCacheX[i] = new IntCache(8); + polyArcCacheY[i] = new IntCache(8); + polyArcCacheWidth[i] = new IntCache(8); + polyArcCacheHeight[i] = new IntCache(8); + polyArcCacheAngle1[i] = new IntCache(8); + polyArcCacheAngle2[i] = new IntCache(8); + } + + for (i = 0; i < 8; i++) + { + shapeDataCache[i] = new IntCache(8); + } + + for (i = 0; i < 8; i++) + { + genericRequestDataCache[i] = new IntCache(8); + } + + for (i = 0; i < 16; i++) + { + renderDataCache[i] = new IntCache(16); + } + + for (i = 0; i < 16; i++) + { + renderCompositeGlyphsDataCache[i] = new IntCache(16); + } + + for (i = 0; i < 3; i++) + { + renderCompositeDataCache[i] = new IntCache(16); + } +} + + +ClientCache::~ClientCache() +{ + unsigned int i; + + for (i = 0; i < 3; i++) + { + delete allocColorRGBCache[i]; + delete convertSelectionAtomCache[i]; + } + + for (i = 0; i < 4; i++) + { + delete clearAreaGeomCache[i]; + } + + for (i = 0; i < 7; i++) + { + delete configureWindowAttrCache[i]; + } + + for (i = 0; i < 6; i++) + { + delete copyAreaGeomCache[i]; + delete copyPlaneGeomCache[i]; + } + + for (i = 0; i < 23; i++) + { + delete createGCAttrCache[i]; + } + + for (i = 0; i < 6; i++) + { + delete createWindowGeomCache[i]; + } + + for (i = 0; i < 15; i++) + { + delete createWindowAttrCache[i]; + } + + for (i = 0; i < 10; i++) + { + delete fillPolyXRelCache[i]; + delete fillPolyXAbsCache[i]; + delete fillPolyYRelCache[i]; + delete fillPolyYAbsCache[i]; + } + + for (i = 0; i < 4; i++) + { + delete polyFillRectangleCacheX[i]; + delete polyFillRectangleCacheY[i]; + delete polyFillRectangleCacheWidth[i]; + delete polyFillRectangleCacheHeight[i]; + } + + for (i = 0; i < 2; i++) + { + delete polyLineCacheX[i]; + delete polyLineCacheY[i]; + } + + for (i = 0; i < 2; i++) + { + delete polyPointCacheX[i]; + delete polyPointCacheY[i]; + } + + for (i = 0; i < 4; i++) + { + delete polyRectangleGeomCache[i]; + } + + for (i = 0; i < 4; i++) + { + delete setClipRectanglesGeomCache[i]; + } + + for (i = 0; i < 2; i++) + { + delete polyFillArcCacheX[i]; + delete polyFillArcCacheY[i]; + delete polyFillArcCacheWidth[i]; + delete polyFillArcCacheHeight[i]; + delete polyFillArcCacheAngle1[i]; + delete polyFillArcCacheAngle2[i]; + } + + for (i = 0; i < 2; i++) + { + delete polyArcCacheX[i]; + delete polyArcCacheY[i]; + delete polyArcCacheWidth[i]; + delete polyArcCacheHeight[i]; + delete polyArcCacheAngle1[i]; + delete polyArcCacheAngle2[i]; + } + + for (i = 0; i < 8; i++) + { + delete shapeDataCache[i]; + } + + for (i = 0; i < 8; i++) + { + delete genericRequestDataCache[i]; + } + + for (i = 0; i < 16; i++) + { + delete renderDataCache[i]; + } + + for (i = 0; i < 16; i++) + { + delete renderCompositeGlyphsDataCache[i]; + } + + for (i = 0; i < 3; i++) + { + delete renderCompositeDataCache[i]; + } +} diff --git a/nxcomp/src/ClientCache.h b/nxcomp/src/ClientCache.h new file mode 100644 index 000000000..ed3361097 --- /dev/null +++ b/nxcomp/src/ClientCache.h @@ -0,0 +1,417 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ClientCache_H +#define ClientCache_H + +#include "Misc.h" + +#include "IntCache.h" +#include "CharCache.h" +#include "OpcodeCache.h" +#include "XidCache.h" +#include "FreeCache.h" + +#include "ChannelCache.h" + +class ClientCache : public ChannelCache +{ + public: + + ClientCache(); + + ~ClientCache(); + + // + // Opcode prediction caches. + // + + OpcodeCache opcodeCache; + + // + // GC and drawables caches. + // + + XidCache gcCache; + FreeCache freeGCCache; + + XidCache drawableCache; + FreeCache freeDrawableCache; + + XidCache windowCache; + FreeCache freeWindowCache; + + // + // General-purpose caches. + // + + IntCache cursorCache; + IntCache colormapCache; + IntCache visualCache; + CharCache depthCache; + CharCache resourceCache; + CharCache methodCache; + + unsigned int lastFont; + + // + // AllocColor request. + // + + IntCache *allocColorRGBCache[3]; + + // + // ChangeProperty request. + // + + CharCache changePropertyFormatCache; + IntCache changePropertyPropertyCache; + IntCache changePropertyTypeCache; + IntCache changePropertyData32Cache; + + // + // ClearArea request. + // + + IntCache *clearAreaGeomCache[4]; + + // + // ConfigureWindow request. + // + + IntCache configureWindowBitmaskCache; + IntCache *configureWindowAttrCache[7]; + + // + // ConvertSelection request. + // + + IntCache convertSelectionRequestorCache; + IntCache* convertSelectionAtomCache[3]; + unsigned int convertSelectionLastTimestamp; + + // + // CopyArea request. + // + + IntCache *copyAreaGeomCache[6]; + + // + // CopyPlane request. + // + + IntCache *copyPlaneGeomCache[6]; + IntCache copyPlaneBitPlaneCache; + + // + // CreateGC request. + // + + IntCache createGCBitmaskCache; + IntCache *createGCAttrCache[23]; + + // + // CreatePixmap request. + // + + IntCache createPixmapIdCache; + unsigned int createPixmapLastId; + IntCache createPixmapXCache; + IntCache createPixmapYCache; + + // + // CreateWindow request. + // + + IntCache *createWindowGeomCache[6]; + IntCache createWindowBitmaskCache; + IntCache *createWindowAttrCache[15]; + + // + // FillPoly request. + // + + IntCache fillPolyNumPointsCache; + IntCache *fillPolyXRelCache[10]; + IntCache *fillPolyXAbsCache[10]; + IntCache *fillPolyYRelCache[10]; + IntCache *fillPolyYAbsCache[10]; + unsigned int fillPolyRecentX[8]; + unsigned int fillPolyRecentY[8]; + unsigned int fillPolyIndex; + + // + // GetSelectionOwner request. + // + + IntCache getSelectionOwnerSelectionCache; + + // + // GrabButton request (also used for GrabPointer). + // + + IntCache grabButtonEventMaskCache; + IntCache grabButtonConfineCache; + CharCache grabButtonButtonCache; + IntCache grabButtonModifierCache; + + // + // GrabKeyboard request. + // + + unsigned int grabKeyboardLastTimestamp; + + // + // ImageText8/16 request. + // + + IntCache imageTextLengthCache; + unsigned int imageTextLastX; + unsigned int imageTextLastY; + IntCache imageTextCacheX; + IntCache imageTextCacheY; + + // + // PolyFillRectangle request. + // + + IntCache *polyFillRectangleCacheX[4]; + IntCache *polyFillRectangleCacheY[4]; + IntCache *polyFillRectangleCacheWidth[4]; + IntCache *polyFillRectangleCacheHeight[4]; + + // + // PolyLine request. + // + + IntCache *polyLineCacheX[2]; + IntCache *polyLineCacheY[2]; + + // + // PolyPoint request. + // + + IntCache *polyPointCacheX[2]; + IntCache *polyPointCacheY[2]; + + // + // PolyRectangle request. + // + + IntCache *polyRectangleGeomCache[4]; + + // + // PolySegment request. + // + + IntCache polySegmentCacheX; + IntCache polySegmentCacheY; + unsigned int polySegmentLastX[2]; + unsigned int polySegmentLastY[2]; + unsigned int polySegmentCacheIndex; + + // + // PolyText8/16 request. + // + + unsigned int polyTextLastX; + unsigned int polyTextLastY; + IntCache polyTextCacheX; + IntCache polyTextCacheY; + IntCache polyTextFontCache; + CharCache polyTextDeltaCache; + + // + // PutImage request. + // + + IntCache putImageWidthCache; + IntCache putImageHeightCache; + unsigned int putImageLastX; + unsigned int putImageLastY; + IntCache putImageXCache; + IntCache putImageYCache; + CharCache putImageLeftPadCache; + + // + // GetImage request. + // + + IntCache getImagePlaneMaskCache; + + // + // QueryColors request. + // + + unsigned int queryColorsLastPixel; + + // + // SetClipRectangles request. + // + + IntCache setClipRectanglesXCache; + IntCache setClipRectanglesYCache; + IntCache *setClipRectanglesGeomCache[4]; + + // + // SetDashes request. + // + + IntCache setDashesLengthCache; + IntCache setDashesOffsetCache; + CharCache setDashesDashCache_[2]; + + // + // SetSelectionOwner request. + // + + IntCache setSelectionOwnerCache; + IntCache setSelectionOwnerTimestampCache; + + // + // TranslateCoords request. + // + + IntCache translateCoordsSrcCache; + IntCache translateCoordsDstCache; + IntCache translateCoordsXCache; + IntCache translateCoordsYCache; + + // + // SendEvent request. + // + + IntCache sendEventMaskCache; + CharCache sendEventCodeCache; + CharCache sendEventByteDataCache; + unsigned int sendEventLastSequence; + IntCache sendEventIntDataCache; + CharCache sendEventEventCache; + + // + // PolyFillArc request. + // + + IntCache *polyFillArcCacheX[2]; + IntCache *polyFillArcCacheY[2]; + IntCache *polyFillArcCacheWidth[2]; + IntCache *polyFillArcCacheHeight[2]; + IntCache *polyFillArcCacheAngle1[2]; + IntCache *polyFillArcCacheAngle2[2]; + + // + // PolyArc request. + // + + IntCache *polyArcCacheX[2]; + IntCache *polyArcCacheY[2]; + IntCache *polyArcCacheWidth[2]; + IntCache *polyArcCacheHeight[2]; + IntCache *polyArcCacheAngle1[2]; + IntCache *polyArcCacheAngle2[2]; + + // + // PutPackedImage request. + // + + IntCache putPackedImageSrcLengthCache; + IntCache putPackedImageDstLengthCache; + + // + // Shape extension requests. + // + + CharCache shapeOpcodeCache; + IntCache *shapeDataCache[8]; + + // + // Generic requests. + // + + CharCache genericRequestOpcodeCache; + IntCache *genericRequestDataCache[8]; + + // + // Render extension requests. + // + + OpcodeCache renderOpcodeCache; + + CharCache renderOpCache; + + XidCache renderSrcPictureCache; + XidCache renderMaskPictureCache; + XidCache renderDstPictureCache; + FreeCache renderFreePictureCache; + + IntCache renderGlyphSetCache; + FreeCache renderFreeGlyphSetCache; + + IntCache renderIdCache; + IntCache renderLengthCache; + IntCache renderFormatCache; + IntCache renderValueMaskCache; + IntCache renderNumGlyphsCache; + + IntCache renderXCache; + IntCache renderYCache; + + unsigned int renderLastX; + unsigned int renderLastY; + + IntCache renderWidthCache; + IntCache renderHeightCache; + + unsigned int renderLastId; + + IntCache *renderDataCache[16]; + + IntCache renderGlyphXCache; + IntCache renderGlyphYCache; + + unsigned int renderGlyphX; + unsigned int renderGlyphY; + + IntCache *renderCompositeGlyphsDataCache[16]; + unsigned int renderLastCompositeGlyphsData; + + IntCache *renderCompositeDataCache[3]; + + // + // SetCacheParameters request. + // + + IntCache setCacheParametersCache; + + // + // Encode new XID values based + // on the last value encoded. + // + + IntCache lastIdCache; + unsigned int lastId; +}; + +#endif /* ClientCache_H */ diff --git a/nxcomp/src/ClientChannel.cpp b/nxcomp/src/ClientChannel.cpp new file mode 100644 index 000000000..2a182e49f --- /dev/null +++ b/nxcomp/src/ClientChannel.cpp @@ -0,0 +1,7881 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include + +#include "NXproto.h" +#include "NXrender.h" + +#include "ClientChannel.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "StaticCompressor.h" + +#include "Statistics.h" +#include "Proxy.h" + +#include "PutImage.h" +#include "PutPackedImage.h" + +extern Proxy *proxy; + +// +// Set the verbosity level. You also +// need to define OPCODES in Misc.cpp +// if you want literals instead of +// opcodes' numbers. +// + +#define PANIC +#define WARNING +#undef OPCODES +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Log the important tracepoints related +// to writing packets to the peer proxy. +// + +#undef FLUSH + +// +// Log the operations related to splits. +// + +#undef SPLIT + +// +// Define this to trace the invocations +// of the agent's callbacks. +// + +#undef CALLBACK + +// +// By defining this, a simple procedure is activated at +// startup which just allocates and deallocates plenty +// of cache objects. This is used to help determine the +// current memory requirements. +// + +#undef MEMORY + +// +// Inspects target of common X operations. +// + +#undef TARGETS + +#ifdef TARGETS + +#include +#include + +typedef set < unsigned int, less > T_windows; +typedef set < unsigned int, less > T_pixmaps; +typedef map < unsigned int, unsigned int, less > T_gcontexts; + +T_windows windows; +T_pixmaps pixmaps; +T_gcontexts gcontexts; + +#endif + +// +// Define this to log when a channel +// is created or destroyed. +// + +#undef REFERENCES + +// +// Here are the static members. +// + +#ifdef REFERENCES + +int ClientChannel::references_ = 0; + +#endif + +ClientChannel::ClientChannel(Transport *transport, StaticCompressor *compressor) + + : Channel(transport, compressor), readBuffer_(transport_, this) +{ + // + // Sequence number of the next message + // being encoded or decoded. + // + + clientSequence_ = 0; + serverSequence_ = 0; + + // + // Current sequence known by NX agent. + // + + lastSequence_ = 0; + + // + // This is used to test the synchronous + // flush in the proxy. + // + + lastRequest_ = 0; + + // + // Store information about the images + // being streamed. + // + + splitState_.resource = nothing; + splitState_.pending = 0; + splitState_.commit = 0; + splitState_.mode = split_none; + + // + // Number of outstanding tainted replies. + // + + taintCounter_ = 0; + + #ifdef MEMORY + + *logofs << "ClientChannel: Created 1 ClientCache and 1 ServerCache. " + << "You have 30 seconds to check the allocated size.\n" + << logofs_flush; + + sleep(30); + + ClientCache *clientCacheTestArray[100]; + ServerCache *serverCacheTestArray[100]; + + for (int i = 0; i < 100; i++) + { + clientCacheTestArray[i] = new ClientCache(); + } + + *logofs << "ClientChannel: Created further 100 ClientCache. " + << "You have 30 seconds to check the allocated size.\n" + << logofs_flush; + + sleep(30); + + for (int i = 0; i < 100; i++) + { + serverCacheTestArray[i] = new ServerCache(); + } + + *logofs << "ClientChannel: Created further 100 ServerCache. " + << "You have 30 seconds to check the allocated size.\n" + << logofs_flush; + + sleep(30); + + for (int i = 0; i < 100; i++) + { + delete clientCacheTestArray[i]; + delete serverCacheTestArray[i]; + } + + *logofs << "ClientChannel: Deleted 100 ClientCache and 100 ServerCache. " + << "You have 30 seconds to check the allocated size.\n" + << logofs_flush; + + sleep(30); + + #endif + + #ifdef REFERENCES + *logofs << "ClientChannel: Created new object at " + << this << " for FD#" << fd_ << " out of " + << ++references_ << " allocated channels.\n" + << logofs_flush; + #endif +} + +ClientChannel::~ClientChannel() +{ + #ifdef REFERENCES + *logofs << "ClientChannel: Deleted object at " + << this << " for FD#" << fd_ << " out of " + << --references_ << " allocated channels.\n" + << logofs_flush; + #endif +} + +// +// Beginning of handleRead(). +// + +int ClientChannel::handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, + unsigned int length) +{ + #ifdef TEST + *logofs << "handleRead: Called for FD#" << fd_ + << " with " << encodeBuffer.getLength() + << " bytes already encoded.\n" + << logofs_flush; + #endif + + // + // Pointer to located message and + // its size in bytes. + // + + const unsigned char *inputMessage; + unsigned int inputLength; + + // + // Set when message is found in + // cache. + // + + int hit; + + // + // Check if we can borrow the buffer + // from the caller. + // + + if (message != NULL && length != 0) + { + readBuffer_.readMessage(message, length); + } + else + { + // + // Get the data from the transport. + // + + #if defined(TEST) || defined(INFO) + *logofs << "handleRead: Trying to read from FD#" + << fd_ << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + int result = readBuffer_.readMessage(); + + #ifdef DEBUG + *logofs << "handleRead: Read result on FD#" << fd_ + << " is " << result << ".\n" + << logofs_flush; + #endif + + if (result < 0) + { + // + // Let the proxy close the channel. + // + + return -1; + } + else if (result == 0) + { + #if defined(TEST) || defined(INFO) + + *logofs << "handleRead: PANIC! No data read from FD#" + << fd_ << " while encoding messages.\n" + << logofs_flush; + + HandleCleanup(); + + #endif + + return 0; + } + } + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "handleRead: Encoding messages for FD#" << fd_ + << " with " << readBuffer_.getLength() << " bytes " + << "in the buffer.\n" << logofs_flush; + #endif + + // + // Extract any complete message which + // is available in the buffer. + // + + if (proxy -> handleAsyncSwitch(fd_) < 0) + { + return -1; + } + + while ((inputMessage = readBuffer_.getMessage(inputLength)) != NULL) + { + hit = 0; + + if (firstRequest_) + { + // + // Need to add the length of the first + // request as it was not present in + // previous versions. + // + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeValue(inputLength, 8); + + for (unsigned int i = 0; i < inputLength; i++) + { + encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8); + } + + firstRequest_ = 0; + + #if defined(TEST) || defined(OPCODES) + + int bits = encodeBuffer.diffBits(); + + *logofs << "handleRead: Handled first request. " << inputLength + << " bytes in, " << bits << " bits (" << ((float) bits) / 8 + << " bytes) out.\n" << logofs_flush; + #endif + + priority_++; + } + else + { + // + // First of all we get the opcode. + // + + unsigned char inputOpcode = *inputMessage; + + #if defined(TEST) || defined(INFO) + + // + // This is used to test the synchronous + // flush in the parent proxy. + // + + lastRequest_ = inputOpcode; + + #endif + + // + // Check if the request is supported by the + // remote. If not, only handle it locally and + // taint the opcode as a X_NoOperation. Also + // try to short-circuit some replies at this + // side. XSync requests, for example, weight + // for half of the total round-trips. + // + + if (handleTaintRequest(inputOpcode, inputMessage, + inputLength) < 0) + { + return -1; + } + + encodeBuffer.encodeOpcodeValue(inputOpcode, clientCache_ -> opcodeCache); + + // + // Update the current sequence. + // + + clientSequence_++; + clientSequence_ &= 0xffff; + + #ifdef DEBUG + *logofs << "handleRead: Last client sequence number for FD#" + << fd_ << " is " << clientSequence_ << ".\n" + << logofs_flush; + #endif + + // + // If differential compression is disabled + // then use the most simple encoding. + // + + if (control -> LocalDeltaCompression == 0) + { + int result = handleFastReadRequest(encodeBuffer, inputOpcode, + inputMessage, inputLength); + if (result < 0) + { + return -1; + } + else if (result > 0) + { + continue; + } + } + + // + // Go to the message's specific encoding. + // + + switch (inputOpcode) + { + case X_AllocColor: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, + clientCache_ -> colormapCache); + const unsigned char *nextSrc = inputMessage + 8; + unsigned int colorData[3]; + for (unsigned int i = 0; i < 3; i++) + { + unsigned int value = GetUINT(nextSrc, bigEndian_); + encodeBuffer.encodeCachedValue(value, 16, + *(clientCache_ -> allocColorRGBCache[i]), 4); + colorData[i] = value; + nextSrc += 2; + } + + sequenceQueue_.push(clientSequence_, inputOpcode, + colorData[0], colorData[1], colorData[2]); + + priority_++; + } + break; + case X_ReparentWindow: + { + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, bigEndian_), + clientCache_ -> windowCache); + encodeBuffer.encodeValue(GetUINT(inputMessage + 12, bigEndian_), 16, 11); + encodeBuffer.encodeValue(GetUINT(inputMessage + 14, bigEndian_), 16, 11); + } + break; + case X_ChangeProperty: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ChangeProperty); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + unsigned char format = inputMessage[16]; + encodeBuffer.encodeCachedValue(format, 8, + clientCache_ -> changePropertyFormatCache); + unsigned int dataLength = GetULONG(inputMessage + 20, bigEndian_); + encodeBuffer.encodeValue(dataLength, 32, 6); + encodeBuffer.encodeValue(inputMessage[1], 2); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, + clientCache_ -> changePropertyPropertyCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), 29, + clientCache_ -> changePropertyTypeCache, 9); + const unsigned char *nextSrc = inputMessage + 24; + if (format == 8) + { + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, dataLength); + } + else if (format == 32) + { + for (unsigned int i = 0; i < dataLength; i++) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 32, + clientCache_ -> changePropertyData32Cache); + nextSrc += 4; + } + } + else + { + for (unsigned int i = 0; i < dataLength; i++) + { + encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16); + nextSrc += 2; + } + } + } + break; + case X_SendEvent: + { + // + // TODO: This can be improved. In the worst + // cases, it appears to provide a poor 1.6:1 + // ratio. + // + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_SendEvent); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + unsigned int window = GetULONG(inputMessage + 4, bigEndian_); + + if (window == 0 || window == 1) + { + encodeBuffer.encodeBoolValue(1); + encodeBuffer.encodeBoolValue(window); + } + else + { + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeXidValue(window, clientCache_ -> windowCache); + } + + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 32, + clientCache_ -> sendEventMaskCache, 9); + encodeBuffer.encodeCachedValue(*(inputMessage + 12), 8, + clientCache_ -> sendEventCodeCache); + encodeBuffer.encodeCachedValue(*(inputMessage + 13), 8, + clientCache_ -> sendEventByteDataCache); + + unsigned int newSeq = GetUINT(inputMessage + 14, bigEndian_); + unsigned int diffSeq = newSeq - clientCache_ -> sendEventLastSequence; + clientCache_ -> sendEventLastSequence = newSeq; + encodeBuffer.encodeValue(diffSeq, 16, 4); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), 32, + clientCache_ -> sendEventIntDataCache); + + for (unsigned int i = 20; i < 44; i++) + { + encodeBuffer.encodeCachedValue((unsigned int) inputMessage[i], 8, + clientCache_ -> sendEventEventCache); + } + } + break; + case X_ChangeWindowAttributes: + { + encodeBuffer.encodeValue((inputLength - 12) >> 2, 4); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + unsigned int bitmask = GetULONG(inputMessage + 8, bigEndian_); + encodeBuffer.encodeCachedValue(bitmask, 15, + clientCache_ -> createWindowBitmaskCache); + const unsigned char *nextSrc = inputMessage + 12; + unsigned int mask = 0x1; + for (unsigned int j = 0; j < 15; j++) + { + if (bitmask & mask) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 32, + *clientCache_ -> createWindowAttrCache[j]); + nextSrc += 4; + } + mask <<= 1; + } + } + break; + case X_ClearArea: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_ClearArea target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_ClearArea target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_ClearArea target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ClearArea); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + const unsigned char *nextSrc = inputMessage + 8; + for (unsigned int i = 0; i < 4; i++) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *clientCache_ -> clearAreaGeomCache[i], 8); + nextSrc += 2; + } + } + break; + case X_CloseFont: + { + unsigned int font = GetULONG(inputMessage + 4, bigEndian_); + encodeBuffer.encodeValue(font - clientCache_ -> lastFont, 29, 5); + clientCache_ -> lastFont = font; + } + break; + case X_ConfigureWindow: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ConfigureWindow); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + unsigned int bitmask = GetUINT(inputMessage + 8, bigEndian_); + encodeBuffer.encodeCachedValue(bitmask, 7, + clientCache_ -> configureWindowBitmaskCache); + unsigned int mask = 0x1; + const unsigned char *nextSrc = inputMessage + 12; + for (unsigned int i = 0; i < 7; i++) + { + if (bitmask & mask) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), + CONFIGUREWINDOW_FIELD_WIDTH[i], + *clientCache_ -> configureWindowAttrCache[i], 8); + nextSrc += 4; + } + mask <<= 1; + } + } + break; + case X_ConvertSelection: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, + clientCache_ -> convertSelectionRequestorCache, 9); + const unsigned char* nextSrc = inputMessage + 8; + for (unsigned int i = 0; i < 3; i++) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29, + *(clientCache_ -> convertSelectionAtomCache[i]), 9); + nextSrc += 4; + } + unsigned int timestamp = GetULONG(nextSrc, bigEndian_); + encodeBuffer.encodeValue(timestamp - + clientCache_ -> convertSelectionLastTimestamp, 32, 4); + clientCache_ -> convertSelectionLastTimestamp = timestamp; + } + break; + case X_CopyArea: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_CopyArea source id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_CopyArea source id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_CopyArea source id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + t_id = GetULONG(inputMessage + 8, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_CopyArea target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_CopyArea target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_CopyArea target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_CopyArea); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 12, + bigEndian_), clientCache_ -> gcCache); + const unsigned char *nextSrc = inputMessage + 16; + for (unsigned int i = 0; i < 6; i++) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *clientCache_ -> copyAreaGeomCache[i], 8); + nextSrc += 2; + } + } + break; + case X_CopyGC: + { + #ifdef TARGETS + + unsigned int s_g_id = GetULONG(inputMessage + 4, bigEndian_); + unsigned int d_g_id = GetULONG(inputMessage + 8, bigEndian_); + + *logofs << "handleRead: X_CopyGC source gcontext id is " << s_g_id + << " destination gcontext id is " << d_g_id << ".\n" + << logofs_flush; + + #endif + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> gcCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, + bigEndian_), 23, clientCache_ -> createGCBitmaskCache); + } + break; + case X_CopyPlane: + { + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 12, + bigEndian_), clientCache_ -> gcCache); + const unsigned char *nextSrc = inputMessage + 16; + for (unsigned int i = 0; i < 6; i++) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *clientCache_ -> copyPlaneGeomCache[i], 8); + nextSrc += 2; + } + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 28, bigEndian_), 32, + clientCache_ -> copyPlaneBitPlaneCache, 10); + } + break; + case X_CreateGC: + { + #ifdef TARGETS + + unsigned int g_id = GetULONG(inputMessage + 4, bigEndian_); + unsigned int t_id = GetULONG(inputMessage + 8, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_CreateGC id " << g_id + << " target id is pixmap " << t_id + << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_CreateGC id " << g_id + << " target id is window " << t_id + << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_CreateGC id " << g_id + << " target id is unrecognized.\n" + << logofs_flush; + } + + gcontexts.insert(T_gcontexts::value_type(g_id, t_id)); + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_CreateGC); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeNewXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> lastId, clientCache_ -> lastIdCache, + clientCache_ -> gcCache, + clientCache_ -> freeGCCache); + + const unsigned char *nextSrc = inputMessage + 8; + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> drawableCache); + nextSrc += 4; + unsigned int bitmask = GetULONG(nextSrc, bigEndian_); + nextSrc += 4; + encodeBuffer.encodeCachedValue(bitmask, 23, + clientCache_ -> createGCBitmaskCache); + unsigned int mask = 0x1; + for (unsigned int i = 0; i < 23; i++) + { + if (bitmask & mask) + { + unsigned int value = GetULONG(nextSrc, bigEndian_); + nextSrc += 4; + unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i]; + if (fieldWidth <= 4) + { + encodeBuffer.encodeValue(value, fieldWidth); + } + else + { + encodeBuffer.encodeCachedValue(value, fieldWidth, + *clientCache_ -> createGCAttrCache[i]); + } + } + mask <<= 1; + } + } + break; + case X_ChangeGC: + { + #ifdef TARGETS + + unsigned int g_id = GetULONG(inputMessage + 4, bigEndian_); + + T_gcontexts::iterator i = gcontexts.find(g_id); + + if (i != gcontexts.end()) + { + unsigned int t_id = i -> second; + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_ChangeGC gcontext id is " << g_id + << " target id is pixmap " << t_id << ".\n" + << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_ChangeGC gcontext id is " << g_id + << " target id is window " << t_id << ".\n" + << logofs_flush; + } + else + { + *logofs << "handleRead: X_ChangeGC gcontext is " << g_id + << " target id is unrecognized.\n" + << logofs_flush; + } + } + else + { + *logofs << "handleRead: X_ChangeGC gcontext id " << g_id + << " is unrecognized.\n" << logofs_flush; + } + + gcontexts.erase(g_id); + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ChangeGC); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> gcCache); + const unsigned char *nextSrc = inputMessage + 8; + unsigned int bitmask = GetULONG(nextSrc, bigEndian_); + nextSrc += 4; + encodeBuffer.encodeCachedValue(bitmask, 23, + clientCache_ -> createGCBitmaskCache); + unsigned int mask = 0x1; + for (unsigned int i = 0; i < 23; i++) + { + if (bitmask & mask) + { + unsigned int value = GetULONG(nextSrc, bigEndian_); + nextSrc += 4; + unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i]; + if (fieldWidth <= 4) + { + encodeBuffer.encodeValue(value, fieldWidth); + } + else + { + encodeBuffer.encodeCachedValue(value, fieldWidth, + *clientCache_ -> createGCAttrCache[i]); + } + } + mask <<= 1; + } + } + break; + case X_CreatePixmap: + { + #ifdef TARGETS + + *logofs << "handleRead: X_CreatePixmap depth " << (unsigned) inputMessage[1] + << ", pixmap id " << GetULONG(inputMessage + 4, bigEndian_) + << ", drawable " << GetULONG(inputMessage + 8, bigEndian_) + << ", width " << GetUINT(inputMessage + 12, bigEndian_) + << ", height " << GetUINT(inputMessage + 14, bigEndian_) + << ", size " << GetUINT(inputMessage + 2, bigEndian_) << 2 + << ".\n" << logofs_flush; + + unsigned int p_id = GetULONG(inputMessage + 4, bigEndian_); + unsigned short p_sx = GetUINT(inputMessage + 12, bigEndian_); + unsigned short p_sy = GetUINT(inputMessage + 14, bigEndian_); + + *logofs << "handleRead: X_CreatePixmap id is " << p_id + << " width is " << p_sx << " height is " << p_sy + << ".\n" << logofs_flush; + + if (p_sx * p_sy <= 64 * 64) + { + *logofs << "handleRead: X_CreatePixmap id " << p_id << " of size " + << p_sx << "x" << p_sy << "=" << p_sx * p_sy + << " will be painted at client side.\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_CreatePixmap id " << p_id << " of size " + << p_sx << "x" << p_sy << "=" << p_sx * p_sy + << " will be painted at server side.\n" << logofs_flush; + } + + pixmaps.insert(p_id); + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_CreatePixmap); + + hit = handleEncode(encodeBuffer, clientCache_, messageStore, + inputOpcode, inputMessage, inputLength); + } + break; + case X_CreateWindow: + { + #ifdef TARGETS + + unsigned int w_id = GetULONG(inputMessage + 4, bigEndian_); + + *logofs << "handleRead: X_CreateWindow id is " << w_id + << ".\n" << logofs_flush; + + windows.insert(w_id); + + #endif + + unsigned bitmask = GetULONG(inputMessage + 28, bigEndian_); + encodeBuffer.encodeCachedValue((unsigned int) inputMessage[1], 8, + clientCache_ -> depthCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, bigEndian_), + clientCache_ -> windowCache); + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeNewXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> lastId, clientCache_ -> lastIdCache, + clientCache_ -> windowCache, + clientCache_ -> freeWindowCache); + + const unsigned char *nextSrc = inputMessage + 12; + for (unsigned int i = 0; i < 6; i++) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *clientCache_ -> createWindowGeomCache[i], 8); + nextSrc += 2; + } + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 24, + bigEndian_), 29, clientCache_ -> visualCache); + encodeBuffer.encodeCachedValue(bitmask, 15, + clientCache_ -> createWindowBitmaskCache); + nextSrc = inputMessage + 32; + unsigned int mask = 0x1; + for (unsigned int j = 0; j < 15; j++) + { + if (bitmask & mask) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 32, + *clientCache_ -> createWindowAttrCache[j]); + nextSrc += 4; + } + mask <<= 1; + } + } + break; + case X_DeleteProperty: + { + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + encodeBuffer.encodeValue(GetULONG(inputMessage + 8, bigEndian_), 29, 9); + } + break; + case X_FillPoly: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_FillPoly target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_FillPoly target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_FillPoly target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_FillPoly); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + unsigned int numPoints = ((inputLength - 16) >> 2); + + // Since ProtoStep10 (#issue 108) + encodeBuffer.encodeCachedValue(numPoints, 16, + clientCache_ -> fillPolyNumPointsCache, 4); + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, bigEndian_), + clientCache_ -> gcCache); + encodeBuffer.encodeValue((unsigned int) inputMessage[12], 2); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[13]); + int relativeCoordMode = (inputMessage[13] != 0); + const unsigned char *nextSrc = inputMessage + 16; + unsigned int pointIndex = 0; + + for (unsigned int i = 0; i < numPoints; i++) + { + if (relativeCoordMode) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *clientCache_ -> fillPolyXRelCache[pointIndex], 8); + nextSrc += 2; + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *clientCache_ -> fillPolyYRelCache[pointIndex], 8); + nextSrc += 2; + } + else + { + unsigned int x = GetUINT(nextSrc, bigEndian_); + nextSrc += 2; + unsigned int y = GetUINT(nextSrc, bigEndian_); + nextSrc += 2; + unsigned int j; + for (j = 0; j < 8; j++) + if ((x == clientCache_ -> fillPolyRecentX[j]) && + (y == clientCache_ -> fillPolyRecentY[j])) + break; + if (j < 8) + { + encodeBuffer.encodeBoolValue(1); + encodeBuffer.encodeValue(j, 3); + } + else + { + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeCachedValue(x, 16, + *clientCache_ -> fillPolyXAbsCache[pointIndex], 8); + encodeBuffer.encodeCachedValue(y, 16, + *clientCache_ -> fillPolyYAbsCache[pointIndex], 8); + clientCache_ -> fillPolyRecentX[clientCache_ -> fillPolyIndex] = x; + clientCache_ -> fillPolyRecentY[clientCache_ -> fillPolyIndex] = y; + clientCache_ -> fillPolyIndex++; + if (clientCache_ -> fillPolyIndex == 8) + clientCache_ -> fillPolyIndex = 0; + } + } + + if (++pointIndex == 10) pointIndex = 0; + } + } + break; + case X_FreeColors: + { + unsigned int numPixels = GetUINT(inputMessage + 2, bigEndian_) - 3; + encodeBuffer.encodeValue(numPixels, 16, 4); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, + clientCache_ -> colormapCache); + encodeBuffer.encodeValue(GetULONG(inputMessage + 8, bigEndian_), 32, 4); + const unsigned char *nextSrc = inputMessage + 12; + while (numPixels) + { + encodeBuffer.encodeValue(GetULONG(nextSrc, bigEndian_), 32, 8); + nextSrc += 4; + numPixels--; + } + } + break; + case X_FreeCursor: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), + 29, clientCache_ -> cursorCache, 9); + } + break; + case X_FreeGC: + { + #ifdef TARGETS + + unsigned int g_id = GetULONG(inputMessage + 4, bigEndian_); + + T_gcontexts::iterator i = gcontexts.find(g_id); + + if (i != gcontexts.end()) + { + unsigned int t_id = i -> second; + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_FreeGC gcontext id is " << g_id + << " target id is pixmap " << t_id << ".\n" + << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_FreeGC gcontext id is " << g_id + << " target id is window " << t_id << ".\n" + << logofs_flush; + } + else + { + *logofs << "handleRead: X_FreeGC gcontext id is " << g_id + << " target id is unrecognized.\n" + << logofs_flush; + } + } + else + { + *logofs << "handleRead: X_FreeGC gcontext id " << g_id + << " is unrecognized.\n" << logofs_flush; + } + + gcontexts.erase(g_id); + + #endif + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeFreeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> freeGCCache); + } + break; + case X_FreePixmap: + { + #ifdef TARGETS + + unsigned int p_id = GetULONG(inputMessage + 4, bigEndian_); + + *logofs << "handleRead: X_FreePixmap id is " << p_id << ".\n" << logofs_flush; + + pixmaps.erase(p_id); + + #endif + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeFreeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> freeDrawableCache); + } + break; + case X_GetAtomName: + { + encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 29, 9); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GetGeometry: + { + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> drawableCache); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GetInputFocus: + { + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GetModifierMapping: + { + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GetKeyboardMapping: + { + encodeBuffer.encodeValue((unsigned int) inputMessage[4], 8); + encodeBuffer.encodeValue((unsigned int) inputMessage[5], 8); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GetProperty: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_GetProperty); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + unsigned int property = GetULONG(inputMessage + 8, bigEndian_); + + sequenceQueue_.push(clientSequence_, inputOpcode, property); + + priority_++; + + hit = 1; + + break; + } + + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + unsigned int property = GetULONG(inputMessage + 8, bigEndian_); + encodeBuffer.encodeValue(property, 29, 9); + encodeBuffer.encodeValue(GetULONG(inputMessage + 12, bigEndian_), 29, 9); + encodeBuffer.encodeValue(GetULONG(inputMessage + 16, bigEndian_), 32, 2); + encodeBuffer.encodeValue(GetULONG(inputMessage + 20, bigEndian_), 32, 8); + + sequenceQueue_.push(clientSequence_, inputOpcode, property); + + priority_++; + } + break; + case X_GetSelectionOwner: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, + clientCache_ -> getSelectionOwnerSelectionCache, 9); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GrabButton: + { + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, + clientCache_ -> grabButtonEventMaskCache); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[10]); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[11]); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), 29, + clientCache_ -> grabButtonConfineCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), 29, + clientCache_ -> cursorCache, 9); + encodeBuffer.encodeCachedValue(inputMessage[20], 8, + clientCache_ -> grabButtonButtonCache); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 22, bigEndian_), 16, + clientCache_ -> grabButtonModifierCache); + } + break; + case X_GrabPointer: + { + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, + clientCache_ -> grabButtonEventMaskCache); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[10]); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[11]); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, + bigEndian_), 29, + clientCache_ -> grabButtonConfineCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, + bigEndian_), 29, clientCache_ -> cursorCache, 9); + + unsigned int timestamp = GetULONG(inputMessage + 20, bigEndian_); + encodeBuffer.encodeValue(timestamp - + clientCache_ -> grabKeyboardLastTimestamp, 32, 4); + clientCache_ -> grabKeyboardLastTimestamp = timestamp; + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GrabKeyboard: + { + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + unsigned int timestamp = GetULONG(inputMessage + 8, bigEndian_); + encodeBuffer.encodeValue(timestamp - + clientCache_ -> grabKeyboardLastTimestamp, 32, 4); + clientCache_ -> grabKeyboardLastTimestamp = timestamp; + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[12]); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[13]); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GrabServer: + case X_UngrabServer: + case X_NoOperation: + { + } + break; + case X_PolyText8: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_PolyText8 target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_PolyText8 target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_PolyText8 target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyText8); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + unsigned int x = GetUINT(inputMessage + 12, bigEndian_); + int xDiff = x - clientCache_ -> polyTextLastX; + clientCache_ -> polyTextLastX = x; + encodeBuffer.encodeCachedValue(xDiff, 16, + clientCache_ -> polyTextCacheX); + unsigned int y = GetUINT(inputMessage + 14, bigEndian_); + int yDiff = y - clientCache_ -> polyTextLastY; + clientCache_ -> polyTextLastY = y; + encodeBuffer.encodeCachedValue(yDiff, 16, + clientCache_ -> polyTextCacheY); + const unsigned char *end = inputMessage + inputLength - 1; + const unsigned char *nextSrc = inputMessage + 16; + while (nextSrc < end) + { + unsigned int textLength = (unsigned int) *nextSrc++; + encodeBuffer.encodeBoolValue(1); + encodeBuffer.encodeValue(textLength, 8); + if (textLength == 255) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, 1), 29, + clientCache_ -> polyTextFontCache); + nextSrc += 4; + } + else + { + encodeBuffer.encodeCachedValue(*nextSrc++, 8, + clientCache_ -> polyTextDeltaCache); + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, textLength); + nextSrc += textLength; + } + } + encodeBuffer.encodeBoolValue(0); + } + break; + case X_PolyText16: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_PolyText16 target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_PolyText16 target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_PolyText16 target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyText16); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + unsigned int x = GetUINT(inputMessage + 12, bigEndian_); + int xDiff = x - clientCache_ -> polyTextLastX; + clientCache_ -> polyTextLastX = x; + encodeBuffer.encodeCachedValue(xDiff, 16, + clientCache_ -> polyTextCacheX); + unsigned int y = GetUINT(inputMessage + 14, bigEndian_); + int yDiff = y - clientCache_ -> polyTextLastY; + clientCache_ -> polyTextLastY = y; + encodeBuffer.encodeCachedValue(yDiff, 16, + clientCache_ -> polyTextCacheY); + const unsigned char *end = inputMessage + inputLength - 1; + const unsigned char *nextSrc = inputMessage + 16; + while (nextSrc < end) + { + unsigned int textLength = (unsigned int) *nextSrc++; + encodeBuffer.encodeBoolValue(1); + encodeBuffer.encodeValue(textLength, 8); + if (textLength == 255) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, 1), 29, + clientCache_ -> polyTextFontCache); + nextSrc += 4; + } + else + { + encodeBuffer.encodeCachedValue(*nextSrc++, 8, + clientCache_ -> polyTextDeltaCache); + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, textLength * 2); + nextSrc += textLength * 2; + } + } + encodeBuffer.encodeBoolValue(0); + } + break; + case X_ImageText8: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_ImageText8 target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_ImageText8 target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_ImageText8 target id " + << t_id << " is unrecognized.\n" + << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ImageText8); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + unsigned int textLength = (unsigned int) inputMessage[1]; + encodeBuffer.encodeCachedValue(textLength, 8, + clientCache_ -> imageTextLengthCache, 4); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + unsigned int x = GetUINT(inputMessage + 12, bigEndian_); + int xDiff = x - clientCache_ -> imageTextLastX; + clientCache_ -> imageTextLastX = x; + encodeBuffer.encodeCachedValue(xDiff, 16, + clientCache_ -> imageTextCacheX); + unsigned int y = GetUINT(inputMessage + 14, bigEndian_); + int yDiff = y - clientCache_ -> imageTextLastY; + clientCache_ -> imageTextLastY = y; + encodeBuffer.encodeCachedValue(yDiff, 16, + clientCache_ -> imageTextCacheY); + const unsigned char *nextSrc = inputMessage + 16; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, textLength); + } + break; + case X_ImageText16: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_ImageText16 target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_ImageText16 target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_ImageText16 target id " + << t_id << " is unrecognized.\n" + << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ImageText16); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + unsigned int textLength = (unsigned int) inputMessage[1]; + encodeBuffer.encodeCachedValue(textLength, 8, + clientCache_ -> imageTextLengthCache, 4); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + unsigned int x = GetUINT(inputMessage + 12, bigEndian_); + int xDiff = x - clientCache_ -> imageTextLastX; + clientCache_ -> imageTextLastX = x; + encodeBuffer.encodeCachedValue(xDiff, 16, + clientCache_ -> imageTextCacheX); + unsigned int y = GetUINT(inputMessage + 14, bigEndian_); + int yDiff = y - clientCache_ -> imageTextLastY; + clientCache_ -> imageTextLastY = y; + encodeBuffer.encodeCachedValue(yDiff, 16, + clientCache_ -> imageTextCacheY); + const unsigned char *nextSrc = inputMessage + 16; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, textLength * 2); + } + break; + case X_InternAtom: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_InternAtom); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + sequenceQueue_.push(clientSequence_, inputOpcode); + + // + // Set the priority, also if doing so will + // penalize all the well written clients + // using XInternAtoms() to pipeline multi- + // ple replies. + // + + priority_++; + + hit = 1; + + break; + } + + unsigned int nameLength = GetUINT(inputMessage + 4, bigEndian_); + encodeBuffer.encodeValue(nameLength, 16, 6); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + const unsigned char *nextSrc = inputMessage + 8; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, nameLength); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_ListExtensions: + { + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_ListFonts: + { + unsigned int textLength = GetUINT(inputMessage + 6, bigEndian_); + encodeBuffer.encodeValue(textLength, 16, 6); + encodeBuffer.encodeValue(GetUINT(inputMessage + 4, bigEndian_), 16, 6); + const unsigned char* nextSrc = inputMessage + 8; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, textLength); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_LookupColor: + case X_AllocNamedColor: + { + unsigned int textLength = GetUINT(inputMessage + 8, bigEndian_); + encodeBuffer.encodeValue(textLength, 16, 6); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), + 29, clientCache_ -> colormapCache); + const unsigned char *nextSrc = inputMessage + 12; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, textLength); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_MapWindow: + case X_UnmapWindow: + case X_MapSubwindows: + case X_GetWindowAttributes: + case X_DestroyWindow: + case X_DestroySubwindows: + case X_QueryPointer: + case X_QueryTree: + { + #ifdef TARGETS + + if (inputOpcode == X_DestroyWindow) + { + unsigned int w_id = GetULONG(inputMessage + 4, bigEndian_); + + *logofs << "handleRead: X_DestroyWindow id is " + << w_id << ".\n" << logofs_flush; + + windows.erase(w_id); + } + + #endif + + if (inputOpcode == X_DestroyWindow) + { + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeFreeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> freeWindowCache); + } + else + { + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> windowCache); + } + + if ((inputOpcode == X_QueryPointer) || + (inputOpcode == X_GetWindowAttributes) || + (inputOpcode == X_QueryTree)) + { + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + } + break; + case X_OpenFont: + { + unsigned int nameLength = GetUINT(inputMessage + 8, bigEndian_); + encodeBuffer.encodeValue(nameLength, 16, 7); + unsigned int font = GetULONG(inputMessage + 4, bigEndian_); + encodeBuffer.encodeValue(font - clientCache_ -> lastFont, 29, 5); + clientCache_ -> lastFont = font; + const unsigned char *nextSrc = inputMessage + 12; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, nameLength); + } + break; + case X_PolyFillRectangle: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_PolyFillRectangle target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_PolyFillRectangle target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_PolyFillRectangle target id " + << t_id << " is unrecognized.\n" + << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyFillRectangle); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0; + unsigned int lastWidth = 0, lastHeight = 0; + + // + // TODO: Could send the size at the beginning + // instead of a bool at each iteration. + // + + for (unsigned int i = 12; i < inputLength;) + { + unsigned int x = GetUINT(inputMessage + i, bigEndian_); + unsigned int newX = x; + x -= lastX; + lastX = newX; + encodeBuffer.encodeCachedValue(x, 16, + *clientCache_ -> polyFillRectangleCacheX[index], 8); + i += 2; + unsigned int y = GetUINT(inputMessage + i, bigEndian_); + unsigned int newY = y; + y -= lastY; + lastY = newY; + encodeBuffer.encodeCachedValue(y, 16, + *clientCache_ -> polyFillRectangleCacheY[index], 8); + i += 2; + unsigned int width = GetUINT(inputMessage + i, bigEndian_); + unsigned int newWidth = width; + width -= lastWidth; + lastWidth = newWidth; + encodeBuffer.encodeCachedValue(width, 16, + *clientCache_ -> polyFillRectangleCacheWidth[index], 8); + i += 2; + unsigned int height = GetUINT(inputMessage + i, bigEndian_); + unsigned int newHeight = height; + height -= lastHeight; + lastHeight = newHeight; + encodeBuffer.encodeCachedValue(height, 16, + *clientCache_ -> polyFillRectangleCacheHeight[index], 8); + i += 2; + + if (++index == 4) index = 0; + + encodeBuffer.encodeBoolValue((i < inputLength) ? 1 : 0); + } + } + break; + case X_PolyFillArc: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_PolyFillArc target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_PolyFillArc target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_PolyFillArc target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyFillArc); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0; + unsigned int lastWidth = 0, lastHeight = 0; + unsigned int lastAngle1 = 0, lastAngle2 = 0; + + // + // TODO: Could send the size at the beginning + // instead of a bool at each iteration. + // + + for (unsigned int i = 12; i < inputLength;) + { + unsigned int x = GetUINT(inputMessage + i, bigEndian_); + unsigned int newX = x; + x -= lastX; + lastX = newX; + encodeBuffer.encodeCachedValue(x, 16, + *clientCache_ -> polyFillArcCacheX[index], 8); + i += 2; + unsigned int y = GetUINT(inputMessage + i, bigEndian_); + unsigned int newY = y; + y -= lastY; + lastY = newY; + encodeBuffer.encodeCachedValue(y, 16, + *clientCache_ -> polyFillArcCacheY[index], 8); + i += 2; + unsigned int width = GetUINT(inputMessage + i, bigEndian_); + unsigned int newWidth = width; + width -= lastWidth; + lastWidth = newWidth; + encodeBuffer.encodeCachedValue(width, 16, + *clientCache_ -> polyFillArcCacheWidth[index], 8); + i += 2; + unsigned int height = GetUINT(inputMessage + i, bigEndian_); + unsigned int newHeight = height; + height -= lastHeight; + lastHeight = newHeight; + encodeBuffer.encodeCachedValue(height, 16, + *clientCache_ -> polyFillArcCacheHeight[index], 8); + i += 2; + unsigned int angle1 = GetUINT(inputMessage + i, bigEndian_); + unsigned int newAngle1 = angle1; + angle1 -= lastAngle1; + lastAngle1 = newAngle1; + encodeBuffer.encodeCachedValue(angle1, 16, + *clientCache_ -> polyFillArcCacheAngle1[index], 8); + i += 2; + unsigned int angle2 = GetUINT(inputMessage + i, bigEndian_); + unsigned int newAngle2 = angle2; + angle2 -= lastAngle2; + lastAngle2 = newAngle2; + encodeBuffer.encodeCachedValue(angle2, 16, + *clientCache_ -> polyFillArcCacheAngle2[index], 8); + i += 2; + + if (++index == 2) index = 0; + + encodeBuffer.encodeBoolValue((i < inputLength) ? 1 : 0); + } + } + break; + case X_PolyArc: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_PolyArc target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_PolyArc target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_PolyArc target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyArc); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0; + unsigned int lastWidth = 0, lastHeight = 0; + unsigned int lastAngle1 = 0, lastAngle2 = 0; + + // + // TODO: Could send the size at the beginning + // instead of a bool at each iteration. + // + + for (unsigned int i = 12; i < inputLength;) + { + unsigned int x = GetUINT(inputMessage + i, bigEndian_); + unsigned int newX = x; + x -= lastX; + lastX = newX; + encodeBuffer.encodeCachedValue(x, 16, + *clientCache_ -> polyArcCacheX[index], 8); + i += 2; + unsigned int y = GetUINT(inputMessage + i, bigEndian_); + unsigned int newY = y; + y -= lastY; + lastY = newY; + encodeBuffer.encodeCachedValue(y, 16, + *clientCache_ -> polyArcCacheY[index], 8); + i += 2; + unsigned int width = GetUINT(inputMessage + i, bigEndian_); + unsigned int newWidth = width; + width -= lastWidth; + lastWidth = newWidth; + encodeBuffer.encodeCachedValue(width, 16, + *clientCache_ -> polyArcCacheWidth[index], 8); + i += 2; + unsigned int height = GetUINT(inputMessage + i, bigEndian_); + unsigned int newHeight = height; + height -= lastHeight; + lastHeight = newHeight; + encodeBuffer.encodeCachedValue(height, 16, + *clientCache_ -> polyArcCacheHeight[index], 8); + i += 2; + unsigned int angle1 = GetUINT(inputMessage + i, bigEndian_); + unsigned int newAngle1 = angle1; + angle1 -= lastAngle1; + lastAngle1 = newAngle1; + encodeBuffer.encodeCachedValue(angle1, 16, + *clientCache_ -> polyArcCacheAngle1[index], 8); + i += 2; + unsigned int angle2 = GetUINT(inputMessage + i, bigEndian_); + unsigned int newAngle2 = angle2; + angle2 -= lastAngle2; + lastAngle2 = newAngle2; + encodeBuffer.encodeCachedValue(angle2, 16, + *clientCache_ -> polyArcCacheAngle2[index], 8); + i += 2; + + if (++index == 2) index = 0; + + encodeBuffer.encodeBoolValue((i < inputLength) ? 1 : 0); + } + } + break; + case X_PolyPoint: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_PolyPoint target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_PolyPoint target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_PolyPoint target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyPoint); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeValue(GetUINT(inputMessage + 2, bigEndian_) - 3, 16, 4); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, bigEndian_), + clientCache_ -> gcCache); + const unsigned char *nextSrc = inputMessage + 12; + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0; + + for (unsigned int i = 12; i < inputLength; i += 4) + { + unsigned int x = GetUINT(nextSrc, bigEndian_); + nextSrc += 2; + unsigned int tmp = x; + x -= lastX; + lastX = tmp; + encodeBuffer.encodeCachedValue(x, 16, + *clientCache_ -> polyPointCacheX[index], 8); + unsigned int y = GetUINT(nextSrc, bigEndian_); + nextSrc += 2; + tmp = y; + y -= lastY; + lastY = tmp; + encodeBuffer.encodeCachedValue(y, 16, + *clientCache_ -> polyPointCacheY[index], 8); + + if (++index == 2) index = 0; + } + } + break; + case X_PolyLine: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_PolyLine target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_PolyLine target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_PolyLine target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyLine); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeValue(GetUINT(inputMessage + 2, bigEndian_) - 3, 16, 4); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + const unsigned char *nextSrc = inputMessage + 12; + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0; + + for (unsigned int i = 12; i < inputLength; i += 4) + { + unsigned int x = GetUINT(nextSrc, bigEndian_); + nextSrc += 2; + unsigned int tmp = x; + x -= lastX; + lastX = tmp; + encodeBuffer.encodeCachedValue(x, 16, + *clientCache_ -> polyLineCacheX[index], 8); + unsigned int y = GetUINT(nextSrc, bigEndian_); + nextSrc += 2; + tmp = y; + y -= lastY; + lastY = tmp; + encodeBuffer.encodeCachedValue(y, 16, + *clientCache_ -> polyLineCacheY[index], 8); + + if (++index == 2) index = 0; + } + } + break; + case X_PolyRectangle: + { + encodeBuffer.encodeValue((GetUINT(inputMessage + 2, + bigEndian_) - 3) >> 1, 16, 3); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + const unsigned char *end = inputMessage + inputLength; + const unsigned char *nextSrc = inputMessage + 12; + while (nextSrc < end) + { + for (unsigned int i = 0; i < 4; i++) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *clientCache_ -> polyRectangleGeomCache[i], 8); + nextSrc += 2; + } + } + } + break; + case X_PolySegment: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_PolySegment target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_PolySegment target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_PolySegment target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolySegment); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + encodeBuffer.encodeValue((GetUINT(inputMessage + 2, + bigEndian_) - 3) >> 1, 16, 4); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 8, + bigEndian_), clientCache_ -> gcCache); + const unsigned char *end = inputMessage + inputLength; + const unsigned char *nextSrc = inputMessage + 12; + // unsigned int index = 0; + // unsigned int lastX1, lastY1, lastX2, lastY2; + while (nextSrc < end) + { + unsigned int x = GetUINT(nextSrc, bigEndian_); + nextSrc += 2; + unsigned int xDiff0 = + x - clientCache_ -> polySegmentLastX[0]; + unsigned int xDiff1 = + x - clientCache_ -> polySegmentLastX[1]; + int xDiff0Abs = (int) xDiff0; + if (xDiff0Abs < 0) + xDiff0Abs = -xDiff0Abs; + int xDiff1Abs = (int) xDiff1; + if (xDiff1Abs < 0) + xDiff1Abs = -xDiff1Abs; + + unsigned int y = GetUINT(nextSrc, bigEndian_); + nextSrc += 2; + unsigned int yDiff0 = + y - clientCache_ -> polySegmentLastY[0]; + unsigned int yDiff1 = + y - clientCache_ -> polySegmentLastY[1]; + int yDiff0Abs = (int) yDiff0; + if (yDiff0Abs < 0) + yDiff0Abs = -yDiff0Abs; + int yDiff1Abs = (int) yDiff1; + if (yDiff1Abs < 0) + yDiff1Abs = -yDiff1Abs; + + int diff0 = xDiff0Abs + yDiff0Abs; + int diff1 = xDiff1Abs + yDiff1Abs; + if (diff0 < diff1) + { + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeCachedValue(xDiff0, 16, + clientCache_ -> polySegmentCacheX, 6); + encodeBuffer.encodeCachedValue(yDiff0, 16, + clientCache_ -> polySegmentCacheY, 6); + } + else + { + encodeBuffer.encodeBoolValue(1); + encodeBuffer.encodeCachedValue(xDiff1, 16, + clientCache_ -> polySegmentCacheX, 6); + encodeBuffer.encodeCachedValue(yDiff1, 16, + clientCache_ -> polySegmentCacheY, 6); + } + + clientCache_ -> polySegmentLastX[clientCache_ -> polySegmentCacheIndex] = x; + clientCache_ -> polySegmentLastY[clientCache_ -> polySegmentCacheIndex] = y; + + clientCache_ -> polySegmentCacheIndex = + clientCache_ -> polySegmentCacheIndex == 1 ? 0 : 1; + } + } + break; + case X_PutImage: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_PutImage target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_PutImage target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_PutImage target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PutImage); + + hit = handleEncode(encodeBuffer, clientCache_, messageStore, + inputOpcode, inputMessage, inputLength); + } + break; + case X_QueryBestSize: + { + encodeBuffer.encodeValue((unsigned int)inputMessage[1], 2); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + encodeBuffer.encodeValue(GetUINT(inputMessage + 8, bigEndian_), 16, 8); + encodeBuffer.encodeValue(GetUINT(inputMessage + 10, bigEndian_), 16, 8); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_QueryColors: + { + // Differential encoding. + encodeBuffer.encodeBoolValue(1); + + unsigned int numColors = ((inputLength - 8) >> 2); + encodeBuffer.encodeValue(numColors, 16, 5); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, + clientCache_ -> colormapCache); + const unsigned char *nextSrc = inputMessage + 8; + unsigned int predictedPixel = clientCache_ -> queryColorsLastPixel; + for (unsigned int i = 0; i < numColors; i++) + { + unsigned int pixel = GetULONG(nextSrc, bigEndian_); + nextSrc += 4; + if (pixel == predictedPixel) + encodeBuffer.encodeBoolValue(1); + else + { + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeValue(pixel, 32, 9); + } + if (i == 0) + clientCache_ -> queryColorsLastPixel = pixel; + predictedPixel = pixel + 1; + } + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_QueryExtension: + { + #ifdef TEST + + char data[256]; + + int length = GetUINT(inputMessage + 4, bigEndian_); + + if (length > 256) + { + length = 256; + } + + strncpy(data, (char *) inputMessage + 8, length); + + *(data + length) = '\0'; + + *logofs << "handleRead: Going to query extension '" + << data << "' for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + unsigned int nameLength = GetUINT(inputMessage + 4, bigEndian_); + encodeBuffer.encodeValue(nameLength, 16, 6); + const unsigned char *nextSrc = inputMessage + 8; + + for (; nameLength; nameLength--) + { + encodeBuffer.encodeValue((unsigned int) *nextSrc++, 8); + } + + unsigned int extension = 0; + + if (strncmp((char *) inputMessage + 8, "SHAPE", 5) == 0) + { + extension = X_NXInternalShapeExtension; + } + else if (strncmp((char *) inputMessage + 8, "RENDER", 6) == 0) + { + extension = X_NXInternalRenderExtension; + } + + sequenceQueue_.push(clientSequence_, inputOpcode, extension); + + priority_++; + } + break; + case X_QueryFont: + { + unsigned int font = GetULONG(inputMessage + 4, bigEndian_); + encodeBuffer.encodeValue(font - clientCache_ -> lastFont, 29, 5); + clientCache_ -> lastFont = font; + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_SetClipRectangles: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_SetClipRectangles); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + hit = 1; + + break; + } + + unsigned int numRectangles = ((inputLength - 12) >> 3); + + // Since ProtoStep9 (#issue 108) + encodeBuffer.encodeValue(numRectangles, 15, 4); + + encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> gcCache); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, + clientCache_ -> setClipRectanglesXCache, 8); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 10, bigEndian_), 16, + clientCache_ -> setClipRectanglesYCache, 8); + const unsigned char *nextSrc = inputMessage + 12; + for (unsigned int i = 0; i < numRectangles; i++) + { + for (unsigned int j = 0; j < 4; j++) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *clientCache_ -> setClipRectanglesGeomCache[j], 8); + nextSrc += 2; + } + } + } + break; + case X_SetDashes: + { + unsigned int numDashes = GetUINT(inputMessage + 10, bigEndian_); + encodeBuffer.encodeCachedValue(numDashes, 16, + clientCache_ -> setDashesLengthCache, 5); + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, bigEndian_), + clientCache_ -> gcCache); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, + clientCache_ -> setDashesOffsetCache, 5); + const unsigned char *nextSrc = inputMessage + 12; + for (unsigned int i = 0; i < numDashes; i++) + encodeBuffer.encodeCachedValue(*nextSrc++, 8, + clientCache_ -> setDashesDashCache_[i & 1], 5); + } + break; + case X_SetSelectionOwner: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, + clientCache_ -> setSelectionOwnerCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, + clientCache_ -> getSelectionOwnerSelectionCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), 32, + clientCache_ -> setSelectionOwnerTimestampCache, 9); + } + break; + case X_TranslateCoords: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_TranslateCoords source id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_TranslateCoords source id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_TranslateCoords source id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + t_id = GetULONG(inputMessage + 8, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_TranslateCoords target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_TranslateCoords target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_TranslateCoords target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_TranslateCoords); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + + hit = 1; + + break; + } + + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, + clientCache_ -> translateCoordsSrcCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, + clientCache_ -> translateCoordsDstCache, 9); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 12, bigEndian_), 16, + clientCache_ -> translateCoordsXCache, 8); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 14, bigEndian_), 16, + clientCache_ -> translateCoordsYCache, 8); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GetImage: + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_GetImage source id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_GetImage source id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_GetImage source id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_GetImage); + + if (handleEncodeCached(encodeBuffer, clientCache_, messageStore, + inputMessage, inputLength)) + { + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + + hit = 1; + + break; + } + + // Format. + encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2); + // Drawable. + encodeBuffer.encodeXidValue(GetULONG(inputMessage + 4, + bigEndian_), clientCache_ -> drawableCache); + // X. + unsigned int x = GetUINT(inputMessage + 8, bigEndian_); + int xDiff = x - clientCache_ -> putImageLastX; + clientCache_ -> putImageLastX = x; + encodeBuffer.encodeCachedValue(xDiff, 16, + clientCache_ -> putImageXCache, 8); + // Y. + unsigned int y = GetUINT(inputMessage + 10, bigEndian_); + int yDiff = y - clientCache_ -> putImageLastY; + clientCache_ -> putImageLastY = y; + encodeBuffer.encodeCachedValue(yDiff, 16, + clientCache_ -> putImageYCache, 8); + // Width. + unsigned int width = GetUINT(inputMessage + 12, bigEndian_); + encodeBuffer.encodeCachedValue(width, 16, + clientCache_ -> putImageWidthCache, 8); + // Height. + unsigned int height = GetUINT(inputMessage + 14, bigEndian_); + encodeBuffer.encodeCachedValue(height, 16, + clientCache_ -> putImageHeightCache, 8); + // Plane mask. + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), 32, + clientCache_ -> getImagePlaneMaskCache, 5); + + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GetPointerMapping: + { + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + case X_GetKeyboardControl: + { + sequenceQueue_.push(clientSequence_, inputOpcode); + + priority_++; + } + break; + default: + { + if (inputOpcode == opcodeStore_ -> renderExtension) + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXInternalRenderExtension); + + hit = handleEncode(encodeBuffer, clientCache_, messageStore, + inputOpcode, inputMessage, inputLength); + } + else if (inputOpcode == opcodeStore_ -> shapeExtension) + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXInternalShapeExtension); + + hit = handleEncode(encodeBuffer, clientCache_, messageStore, + inputOpcode, inputMessage, inputLength); + } + else if (inputOpcode == opcodeStore_ -> putPackedImage) + { + #ifdef TARGETS + + unsigned int t_id = GetULONG(inputMessage + 4, bigEndian_); + + if (pixmaps.find(t_id) != pixmaps.end()) + { + *logofs << "handleRead: X_NXPutPackedImage target id is pixmap " + << t_id << ".\n" << logofs_flush; + } + else if (windows.find(t_id) != windows.end()) + { + *logofs << "handleRead: X_NXPutPackedImage target id is window " + << t_id << ".\n" << logofs_flush; + } + else + { + *logofs << "handleRead: X_NXPutPackedImage target id " << t_id + << " is unrecognized.\n" << logofs_flush; + } + + #endif + + #ifdef DEBUG + *logofs << "handleRead: Encoding packed image request for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + // + // The field carries the destination data + // length. We add the request's size of + // the final X_PutImage. + // + + unsigned int outputLength = GetULONG(inputMessage + 20, bigEndian_) + 24; + + statistics -> addPackedBytesIn(inputLength); + + statistics -> addPackedBytesOut(outputLength); + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXPutPackedImage); + + hit = handleEncode(encodeBuffer, clientCache_, messageStore, + inputOpcode, inputMessage, inputLength); + } + else if (inputOpcode == opcodeStore_ -> setUnpackColormap) + { + #ifdef DEBUG + *logofs << "handleRead: Encoding set unpack colormap request " + << "for FD#" << fd_ << " with size " << inputLength + << ".\n" << logofs_flush; + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXSetUnpackColormap); + + hit = handleEncode(encodeBuffer, clientCache_, messageStore, + inputOpcode, inputMessage, inputLength); + } + else if (inputOpcode == opcodeStore_ -> setUnpackAlpha) + { + #ifdef DEBUG + *logofs << "handleRead: Encoding set unpack alpha request " + << "for FD#" << fd_ << " with size " << inputLength + << ".\n" << logofs_flush; + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXSetUnpackAlpha); + + hit = handleEncode(encodeBuffer, clientCache_, messageStore, + inputOpcode, inputMessage, inputLength); + } + else if (inputOpcode == opcodeStore_ -> setUnpackGeometry) + { + #ifdef DEBUG + *logofs << "handleRead: Encoding set unpack geometry request " + << "for FD#" << fd_ << " with size " << inputLength + << ".\n" << logofs_flush; + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXSetUnpackGeometry); + + hit = handleEncode(encodeBuffer, clientCache_, messageStore, + inputOpcode, inputMessage, inputLength); + } + else if (inputOpcode == opcodeStore_ -> startSplit) + { + if (handleStartSplitRequest(encodeBuffer, inputOpcode, + inputMessage, inputLength) < 0) + { + return -1; + } + } + else if (inputOpcode == opcodeStore_ -> endSplit) + { + if (handleEndSplitRequest(encodeBuffer, inputOpcode, + inputMessage, inputLength) < 0) + { + return -1; + } + } + else if (inputOpcode == opcodeStore_ -> commitSplit) + { + if (handleCommitSplitRequest(encodeBuffer, inputOpcode, + inputMessage, inputLength) < 0) + { + return -1; + } + } + else if (inputOpcode == opcodeStore_ -> abortSplit) + { + if (handleAbortSplitRequest(encodeBuffer, inputOpcode, + inputMessage, inputLength) < 0) + { + return -1; + } + } + else if (inputOpcode == opcodeStore_ -> finishSplit) + { + if (handleFinishSplitRequest(encodeBuffer, inputOpcode, + inputMessage, inputLength) < 0) + { + return -1; + } + } + else if (inputOpcode == opcodeStore_ -> freeSplit) + { + #ifdef DEBUG + *logofs << "handleRead: Encoding free split request " + << "for FD#" << fd_ << " with size " << inputLength + << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(*(inputMessage + 1), 8, + clientCache_ -> resourceCache); + } + else if (inputOpcode == opcodeStore_ -> freeUnpack) + { + #ifdef DEBUG + *logofs << "handleRead: Encoding free unpack request " + << "for FD#" << fd_ << " with size " << inputLength + << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(*(inputMessage + 1), 8, + clientCache_ -> resourceCache); + } + else if (inputOpcode == opcodeStore_ -> getControlParameters) + { + #ifdef DEBUG + *logofs << "handleRead: Encoding get control parameters " + << "request for FD#" << fd_ << " with size " + << inputLength << ".\n" << logofs_flush; + #endif + + // + // Add the reply to the write buffer. If found + // to contain a message, it it will be flushed + // to the X client before leaving the loop. + // + + unsigned char *reply = writeBuffer_.addMessage(32); + + *(reply + 0) = X_Reply; + + PutUINT(clientSequence_, reply + 2, bigEndian_); + + PutULONG(0, reply + 4, bigEndian_); + + // + // Save the sequence number we used + // to auto-generate this reply. + // + + lastSequence_ = clientSequence_; + + #ifdef TEST + *logofs << "handleRead: Registered " << lastSequence_ + << " as last auto-generated sequence number.\n" + << logofs_flush; + #endif + + *(reply + 1) = control -> LinkMode; + + *(reply + 8) = control -> LocalVersionMajor; + *(reply + 9) = control -> LocalVersionMinor; + *(reply + 10) = control -> LocalVersionPatch; + + *(reply + 11) = control -> RemoteVersionMajor; + *(reply + 12) = control -> RemoteVersionMinor; + *(reply + 13) = control -> RemoteVersionPatch; + + PutUINT(control -> SplitTimeout, reply + 14, bigEndian_); + PutUINT(control -> MotionTimeout, reply + 16, bigEndian_); + + *(reply + 18) = control -> SplitMode; + + PutULONG(control -> SplitDataThreshold, reply + 20, bigEndian_); + + *(reply + 24) = control -> PackMethod; + *(reply + 25) = control -> PackQuality; + + *(reply + 26) = control -> LocalDataCompressionLevel; + *(reply + 27) = control -> LocalStreamCompressionLevel; + *(reply + 28) = control -> LocalDeltaCompression; + + *(reply + 29) = (control -> LocalDeltaCompression == 1 && + control -> PersistentCacheEnableLoad == 1); + *(reply + 30) = (control -> LocalDeltaCompression == 1 && + control -> PersistentCacheEnableSave == 1); + *(reply + 31) = (control -> LocalDeltaCompression == 1 && + control -> PersistentCacheEnableLoad == 1 && + control -> PersistentCacheName != NULL); + + if (handleFlush(flush_if_any) < 0) + { + return -1; + } + } + else if (inputOpcode == opcodeStore_ -> getCleanupParameters) + { + #ifdef WARNING + *logofs << "handleRead: WARNING! Encoding fake get cleanup " + << "parameters request for FD#" << fd_ << " with size " + << inputLength << ".\n" << logofs_flush; + #endif + } + else if (inputOpcode == opcodeStore_ -> getImageParameters) + { + #ifdef WARNING + *logofs << "handleRead: WARNING! Encoding fake get cleanup " + << "parameters request for FD#" << fd_ << " with size " + << inputLength << ".\n" << logofs_flush; + #endif + } + else if (inputOpcode == opcodeStore_ -> getUnpackParameters) + { + #ifdef DEBUG + *logofs << "handleRead: Encoding get unpack parameters " + << "request for FD#" << fd_ << " with size " + << inputLength << ".\n" << logofs_flush; + #endif + + sequenceQueue_.push(clientSequence_, inputOpcode); + } + else if (inputOpcode == opcodeStore_ -> getShmemParameters) + { + if (handleShmemRequest(encodeBuffer, inputOpcode, + inputMessage, inputLength) < 0) + { + return -1; + } + } + else if (inputOpcode == opcodeStore_ -> setExposeParameters) + { + // + // Enable or disable expose events + // coming from the real server. + // + + encodeBuffer.encodeBoolValue(*(inputMessage + 4)); + encodeBuffer.encodeBoolValue(*(inputMessage + 5)); + encodeBuffer.encodeBoolValue(*(inputMessage + 6)); + } + else if (inputOpcode == opcodeStore_ -> setCacheParameters) + { + if (handleCacheRequest(encodeBuffer, inputOpcode, + inputMessage, inputLength) < 0) + { + return -1; + } + } + else if (inputOpcode == opcodeStore_ -> getFontParameters) + { + if (handleFontRequest(encodeBuffer, inputOpcode, + inputMessage, inputLength) < 0) + { + return -1; + } + } + else + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXInternalGenericRequest); + + hit = handleEncode(encodeBuffer, clientCache_, messageStore, + inputOpcode, inputMessage, inputLength); + + // + // Don't flush if the opcode is unrecognized. + // We may optionally flush it is an extension + // but would penalize the well written clients. + // + // if (inputOpcode > 127) + // { + // priority_++; + // } + // + } + } + } // End of switch on opcode. + + int bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) + + const char *cacheString = (hit ? "cached " : ""); + + *logofs << "handleRead: Handled " << cacheString << "request OPCODE#" + << (unsigned int) inputOpcode << " (" << DumpOpcode(inputOpcode) + << ")" << " for FD#" << fd_ << " sequence " << clientSequence_ + << ". " << inputLength << " bytes in, " << bits << " bits (" + << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; + + #endif + + if (hit) + { + statistics -> addCachedRequest(inputOpcode); + } + + statistics -> addRequestBits(inputOpcode, inputLength << 3, bits); + + if (inputOpcode == opcodeStore_ -> renderExtension) + { + if (hit) + { + statistics -> addRenderCachedRequest(*(inputMessage + 1)); + } + + statistics -> addRenderRequestBits(*(inputMessage + 1), inputLength << 3, bits); + } + + } // End if (firstRequest_)... else ... + + } // End of while ((inputMessage = readBuffer_.getMessage(inputLength)) != 0) ... + + // + // Check if we need to flush because of + // prioritized data. + // + + if (priority_ > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleRead: WARNING! Requesting flush " + << "because of " << priority_ << " prioritized " + << "messages for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + if (proxy -> handleAsyncPriority() < 0) + { + return -1; + } + + // + // Reset the priority flag. + // + + priority_ = 0; + } + + // + // Flush if we exceeded the token length. + // + + if (proxy -> canAsyncFlush() == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleRead: WARNING! Requesting flush " + << "because of token length exceeded.\n" + << logofs_flush; + #endif + + if (proxy -> handleAsyncFlush() < 0) + { + return -1; + } + } + + #if defined(TEST) || defined(INFO) + + if (transport_ -> pending() != 0 || + readBuffer_.checkMessage() != 0) + { + *logofs << "handleRead: PANIC! Buffer for X descriptor FD#" + << fd_ << " has " << transport_ -> pending() + << " bytes to read.\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + // + // Reset the read buffer. + // + + readBuffer_.fullReset(); + + return 1; +} + +// +// End of handleRead(). +// + +// +// Beginning of handleWrite(). +// + +int ClientChannel::handleWrite(const unsigned char *message, unsigned int length) +{ + #ifdef TEST + *logofs << "handleWrite: Called for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + // + // Create the buffer from which to + // decode messages. + // + + DecodeBuffer decodeBuffer(message, length); + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "handleWrite: Decoding messages for FD#" << fd_ + << " with " << length << " bytes in the buffer.\n" + << logofs_flush; + #endif + + if (firstReply_) + { + #ifdef TEST + *logofs << "handleWrite: First reply detected.\n" << logofs_flush; + #endif + + unsigned int outputOpcode; + + decodeBuffer.decodeValue(outputOpcode, 8); + unsigned int secondByte; + decodeBuffer.decodeValue(secondByte, 8); + unsigned int major; + decodeBuffer.decodeValue(major, 16); + unsigned int minor; + decodeBuffer.decodeValue(minor, 16); + unsigned int extraLength; + decodeBuffer.decodeValue(extraLength, 16); + unsigned int outputLength = 8 + (extraLength << 2); + + unsigned char *outputMessage = writeBuffer_.addMessage(outputLength); + *outputMessage = (unsigned char) outputOpcode; + outputMessage[1] = (unsigned char) secondByte; + PutUINT(major, outputMessage + 2, bigEndian_); + PutUINT(minor, outputMessage + 4, bigEndian_); + PutUINT(extraLength, outputMessage + 6, bigEndian_); + unsigned char *nextDest = outputMessage + 8; + unsigned int cached; + decodeBuffer.decodeBoolValue(cached); + + if (cached) + { + memcpy(nextDest, ServerCache::lastInitReply.getData(), outputLength - 8); + } + else + { + for (unsigned i = 8; i < outputLength; i++) + { + unsigned int nextByte; + decodeBuffer.decodeValue(nextByte, 8); + *nextDest++ = (unsigned char) nextByte; + } + + ServerCache::lastInitReply.set(outputLength - 8, outputMessage + 8); + } + + imageByteOrder_ = outputMessage[30]; + bitmapBitOrder_ = outputMessage[31]; + scanlineUnit_ = outputMessage[32]; + scanlinePad_ = outputMessage[33]; + + firstReply_ = 0; + + } // End of if (firstReply_) + + // + // This was previously in a 'else' block. + // Due to the way the first request was + // handled, we could not decode multiple + // messages in the first frame. + // + + { // Start of the decoding block. + + #ifdef DEBUG + *logofs << "handleWrite: Starting loop on opcodes.\n" + << logofs_flush; + #endif + + unsigned char outputOpcode; + + // + // NX client needs this line to consider + // the initialization phase successfully + // completed. + // + + if (firstClient_ == -1) + { + cerr << "Info" << ": Established X client connection.\n" ; + + firstClient_ = fd_; + } + + while (decodeBuffer.decodeOpcodeValue(outputOpcode, serverCache_ -> opcodeCache, 1)) + { + #ifdef DEBUG + *logofs << "handleWrite: Decoded a new OPCODE#" + << (unsigned int) outputOpcode << ".\n" + << logofs_flush; + #endif + + unsigned char *outputMessage = NULL; + unsigned int outputLength = 0; + + // + // General-purpose temp variables + // for decoding ints and chars. + // + + unsigned int value = 0; + unsigned char cValue = 0; + + // + // Check first if we need to abort any split, + // then if this is a reply, finally if it is + // en event or error. + // + + if (outputOpcode == opcodeStore_ -> splitEvent) + { + // + // It's an abort split, not a normal + // burst of proxy data. + // + + handleSplitEvent(decodeBuffer); + + continue; + } + else if (outputOpcode == X_Reply) + { + #ifdef DEBUG + *logofs << "handleWrite: Decoding sequence number of reply.\n" + << logofs_flush; + #endif + + unsigned int sequenceNum; + unsigned int sequenceDiff; + + decodeBuffer.decodeCachedValue(sequenceDiff, 16, + serverCache_ -> replySequenceCache, 7); + + sequenceNum = (serverSequence_ + sequenceDiff) & 0xffff; + + serverSequence_ = sequenceNum; + + #ifdef DEBUG + *logofs << "handleWrite: Last server sequence number for FD#" + << fd_ << " is " << serverSequence_ << " with " + << "difference " << sequenceDiff << ".\n" + << logofs_flush; + #endif + + // + // In case of reply we can follow the X server and + // override any event's sequence number generated + // by this side. + // + + #ifdef TEST + *logofs << "handleWrite: Updating last event's sequence " + << lastSequence_ << " to reply's sequence number " + << serverSequence_ << " for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + lastSequence_ = serverSequence_; + + unsigned short int requestSequenceNum; + unsigned char requestOpcode; + + #ifdef DEBUG + + requestSequenceNum = 0; + requestOpcode = 0; + + *logofs << "handleWrite: Peek of sequence number returns "; + + *logofs << sequenceQueue_.peek(requestSequenceNum, requestOpcode); + + *logofs << " with sequence " << requestSequenceNum << " and opcode " + << (unsigned int) requestOpcode << ".\n" << logofs_flush; + + #endif + + if (sequenceQueue_.peek(requestSequenceNum, requestOpcode) == 1 && + (requestSequenceNum == sequenceNum)) + { + unsigned int requestData[3]; + + sequenceQueue_.pop(requestSequenceNum, requestOpcode, + requestData[0], requestData[1], requestData[2]); + + #ifdef DEBUG + *logofs << "handleWrite: Identified reply to OPCODE#" + << (unsigned int) requestOpcode << ".\n" + << logofs_flush; + #endif + + // + // Is differential encoding disabled? + // + + if (control -> RemoteDeltaCompression == 0) + { + int result = handleFastWriteReply(decodeBuffer, requestOpcode, + outputMessage, outputLength); + if (result < 0) + { + return -1; + } + else if (result > 0) + { + continue; + } + } + + switch (requestOpcode) + { + case X_AllocColor: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + unsigned char *nextDest = outputMessage + 8; + for (unsigned int i = 0; i < 3; i++) + { + decodeBuffer.decodeBoolValue(value); + if (value) + { + PutUINT(requestData[i], nextDest, bigEndian_); + } + else + { + decodeBuffer.decodeValue(value, 16, 6); + PutUINT(requestData[i] + value, nextDest, bigEndian_); + } + nextDest += 2; + } + decodeBuffer.decodeValue(value, 32, 9); + PutULONG(value, outputMessage + 16, bigEndian_); + } + break; + case X_GetAtomName: + { + unsigned int nameLength; + decodeBuffer.decodeValue(nameLength, 16, 6); + outputLength = RoundUp4(nameLength) + 32; + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(nameLength, outputMessage + 8, bigEndian_); + unsigned char* nextDest = outputMessage + 32; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, nameLength); + } + break; + case X_GetGeometry: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(cValue, 8, + serverCache_ -> depthCache); + outputMessage[1] = cValue; + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> getGeometryRootCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + for (unsigned int i = 0; i < 5; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *serverCache_ -> getGeometryGeomCache[i], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + } + break; + case X_GetInputFocus: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 2); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> getInputFocusWindowCache); + PutULONG(value, outputMessage + 8, bigEndian_); + } + break; + case X_GetKeyboardMapping: + { + decodeBuffer.decodeBoolValue(value); + if (value) + { + unsigned int dataLength = + ServerCache::getKeyboardMappingLastMap.getLength(); + outputLength = 32 + dataLength; + outputMessage = writeBuffer_.addMessage(outputLength); + outputMessage[1] = + ServerCache::getKeyboardMappingLastKeysymsPerKeycode; + memcpy(outputMessage + 32, + ServerCache::getKeyboardMappingLastMap.getData(), + dataLength); + break; + } + unsigned int numKeycodes; + decodeBuffer.decodeValue(numKeycodes, 8); + unsigned int keysymsPerKeycode; + decodeBuffer.decodeValue(keysymsPerKeycode, 8, 4); + ServerCache::getKeyboardMappingLastKeysymsPerKeycode = + keysymsPerKeycode; + outputLength = 32 + numKeycodes * keysymsPerKeycode * 4; + outputMessage = writeBuffer_.addMessage(outputLength); + outputMessage[1] = (unsigned char) keysymsPerKeycode; + unsigned char *nextDest = outputMessage + 32; + unsigned char previous = 0; + for (unsigned int count = numKeycodes * keysymsPerKeycode; + count; --count) + { + decodeBuffer.decodeBoolValue(value); + if (value) + PutULONG((unsigned int) NoSymbol, nextDest, bigEndian_); + else + { + unsigned int keysym; + decodeBuffer.decodeCachedValue(keysym, 24, + serverCache_ -> getKeyboardMappingKeysymCache, 9); + decodeBuffer.decodeCachedValue(cValue, 8, + serverCache_ -> getKeyboardMappingLastByteCache, 5); + previous += cValue; + PutULONG((keysym << 8) | previous, nextDest, bigEndian_); + } + nextDest += 4; + } + ServerCache::getKeyboardMappingLastMap.set(outputLength - 32, + outputMessage + 32); + } + break; + case X_GetModifierMapping: + { + unsigned int keycodesPerModifier; + decodeBuffer.decodeValue(keycodesPerModifier, 8); + outputLength = 32 + (keycodesPerModifier << 3); + outputMessage = writeBuffer_.addMessage(outputLength); + outputMessage[1] = (unsigned char) keycodesPerModifier; + unsigned char *nextDest = outputMessage + 32; + decodeBuffer.decodeBoolValue(value); + if (value) + { + memcpy(outputMessage + 32, + ServerCache::getModifierMappingLastMap.getData(), + ServerCache::getModifierMappingLastMap.getLength()); + break; + } + for (unsigned int count = outputLength - 32; count; count--) + { + decodeBuffer.decodeBoolValue(value); + if (value) + *nextDest++ = 0; + else + { + decodeBuffer.decodeValue(value, 8); + *nextDest++ = value; + } + } + ServerCache::getModifierMappingLastMap.set(outputLength - 32, + outputMessage + 32); + } + break; + case X_GetProperty: + { + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_GetProperty); + + handleDecode(decodeBuffer, serverCache_, messageStore, + requestOpcode, outputMessage, outputLength); + } + break; + case X_GetSelectionOwner: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> getSelectionOwnerCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + } + break; + case X_GetWindowAttributes: + { + outputLength = 44; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 2); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> visualCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> getWindowAttributesClassCache, 3); + PutUINT(value, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(cValue, 8, + serverCache_ -> getWindowAttributesBitGravityCache); + outputMessage[14] = cValue; + decodeBuffer.decodeCachedValue(cValue, 8, + serverCache_ -> getWindowAttributesWinGravityCache); + outputMessage[15] = cValue; + decodeBuffer.decodeCachedValue(value, 32, + serverCache_ -> getWindowAttributesPlanesCache, 9); + PutULONG(value, outputMessage + 16, bigEndian_); + decodeBuffer.decodeCachedValue(value, 32, + serverCache_ -> getWindowAttributesPixelCache, 9); + PutULONG(value, outputMessage + 20, bigEndian_); + decodeBuffer.decodeBoolValue(value); + outputMessage[24] = (unsigned char) value; + decodeBuffer.decodeBoolValue(value); + outputMessage[25] = (unsigned char) value; + decodeBuffer.decodeValue(value, 2); + outputMessage[26] = (unsigned char) value; + decodeBuffer.decodeBoolValue(value); + outputMessage[27] = (unsigned char) value; + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> colormapCache, 9); + PutULONG(value, outputMessage + 28, bigEndian_); + decodeBuffer.decodeCachedValue(value, 32, + serverCache_ -> getWindowAttributesAllEventsCache); + PutULONG(value, outputMessage + 32, bigEndian_); + decodeBuffer.decodeCachedValue(value, 32, + serverCache_ -> getWindowAttributesYourEventsCache); + PutULONG(value, outputMessage + 36, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> getWindowAttributesDontPropagateCache); + PutUINT(value, outputMessage + 40, bigEndian_); + } + break; + case X_GrabKeyboard: + case X_GrabPointer: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 3); + outputMessage[1] = (unsigned char) value; + } + break; + case X_InternAtom: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 29, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + } + break; + case X_ListExtensions: + { + decodeBuffer.decodeValue(value, 32, 8); + outputLength = 32 + (value << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + unsigned int numExtensions; + decodeBuffer.decodeValue(numExtensions, 8); + outputMessage[1] = (unsigned char) numExtensions; + unsigned char *nextDest = outputMessage + 32; + for (; numExtensions; numExtensions--) + { + unsigned int length; + decodeBuffer.decodeValue(length, 8); + *nextDest++ = (unsigned char) length; + for (; length; length--) + { + decodeBuffer.decodeValue(value, 8); + *nextDest++ = value; + } + } + } + break; + case X_ListFonts: + { + // + // Differential compression can achieve a 12:1 to 14:1 + // ratio, while the best ZLIB compression can achieve + // a mere 4:1 to 5:1. In the first case, though, the + // huge amount of data constituting the message would + // be stored uncompressed at the remote side. We need + // to find a compromise. The solution is to use diffe- + // rential compression at startup and ZLIB compression + // later on. + // + + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_ListFonts); + + if (handleDecodeCached(decodeBuffer, serverCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + decodeBuffer.decodeValue(value, 32, 8); + outputLength = 32 + (value << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + unsigned int numFonts; + decodeBuffer.decodeValue(numFonts, 16, 6); + PutUINT(numFonts, outputMessage + 8, bigEndian_); + + // Differential or plain data compression? + decodeBuffer.decodeBoolValue(value); + + if (value) + { + unsigned char* nextDest = outputMessage + 32; + for (; numFonts; numFonts--) + { + unsigned int length; + decodeBuffer.decodeValue(length, 8); + *nextDest++ = (unsigned char)length; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, length); + nextDest += length; + } + + handleSave(messageStore, outputMessage, outputLength); + } + else + { + const unsigned char *compressedData = NULL; + unsigned int compressedDataSize = 0; + + int decompressed = handleDecompress(decodeBuffer, requestOpcode, messageStore -> dataOffset, + outputMessage, outputLength, compressedData, + compressedDataSize); + if (decompressed < 0) + { + return -1; + } + else if (decompressed > 0) + { + handleSave(messageStore, outputMessage, outputLength, + compressedData, compressedDataSize); + } + else + { + handleSave(messageStore, outputMessage, outputLength); + } + } + } + break; + case X_LookupColor: + case X_AllocNamedColor: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + unsigned char *nextDest = outputMessage + 8; + if (requestOpcode == X_AllocNamedColor) + { + decodeBuffer.decodeValue(value, 32, 9); + PutULONG(value, nextDest, bigEndian_); + nextDest += 4; + } + unsigned int count = 3; + do + { + decodeBuffer.decodeValue(value, 16, 9); + PutUINT(value, nextDest, bigEndian_); + unsigned int visualColor; + decodeBuffer.decodeValue(visualColor, 16, 5); + visualColor += value; + visualColor &= 0xffff; + PutUINT(visualColor, nextDest + 6, bigEndian_); + nextDest += 2; + } + while (--count); + } + break; + case X_QueryBestSize: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 16, 8); + PutUINT(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeValue(value, 16, 8); + PutUINT(value, outputMessage + 10, bigEndian_); + } + break; + case X_QueryColors: + { + // Differential or plain data compression? + decodeBuffer.decodeBoolValue(value); + + if (value) + { + decodeBuffer.decodeBoolValue(value); + if (value) + { + unsigned int numColors = + serverCache_ -> queryColorsLastReply.getLength() / 6; + outputLength = 32 + (numColors << 3); + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(numColors, outputMessage + 8, bigEndian_); + const unsigned char *nextSrc = + serverCache_ -> queryColorsLastReply.getData(); + unsigned char *nextDest = outputMessage + 32; + for (; numColors; numColors--) + { + for (unsigned int i = 0; i < 6; i++) + *nextDest++ = *nextSrc++; + nextDest += 2; + } + } + else + { + unsigned int numColors; + decodeBuffer.decodeValue(numColors, 16, 5); + outputLength = 32 + (numColors << 3); + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(numColors, outputMessage + 8, bigEndian_); + unsigned char *nextDest = outputMessage + 32; + for (unsigned int c = 0; c < numColors; c++) + { + for (unsigned int i = 0; i < 3; i++) + { + decodeBuffer.decodeValue(value, 16); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + } + serverCache_ -> queryColorsLastReply.set(numColors * 6, + outputMessage + 32); + const unsigned char *nextSrc = nextDest - 1; + nextDest = outputMessage + 32 + ((numColors - 1) << 3) + 5; + for (; numColors > 1; numColors--) + { + for (unsigned int i = 0; i < 6; i++) + *nextDest-- = *nextSrc--; + nextDest -= 2; + } + } + } + else + { + // Reply length. + unsigned int numColors; + decodeBuffer.decodeValue(numColors, 16, 5); + outputLength = 32 + (numColors << 3); + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(numColors, outputMessage + 8, bigEndian_); + + const unsigned char *compressedData = NULL; + unsigned int compressedDataSize = 0; + + int decompressed = handleDecompress(decodeBuffer, requestOpcode, 32, + outputMessage, outputLength, compressedData, + compressedDataSize); + if (decompressed < 0) + { + return -1; + } + } + } + break; + case X_QueryExtension: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeBoolValue(value); + outputMessage[8] = (unsigned char) value; + decodeBuffer.decodeValue(value, 8); + outputMessage[9] = (unsigned char) value; + decodeBuffer.decodeValue(value, 8); + outputMessage[10] = (unsigned char) value; + decodeBuffer.decodeValue(value, 8); + outputMessage[11] = (unsigned char) value; + + // + // We use a predefined opcode to address + // extensions' message stores, while real + // opcodes are used for communication with + // X server and clients. + // + + if (requestData[0] == X_NXInternalShapeExtension) + { + opcodeStore_ -> shapeExtension = outputMessage[9]; + + #ifdef TEST + *logofs << "handleWrite: Shape extension opcode for FD#" << fd_ + << " is " << (unsigned int) opcodeStore_ -> shapeExtension + << ".\n" << logofs_flush; + #endif + } + else if (requestData[0] == X_NXInternalRenderExtension) + { + opcodeStore_ -> renderExtension = outputMessage[9]; + + #ifdef TEST + *logofs << "handleWrite: Render extension opcode for FD#" << fd_ + << " is " << (unsigned int) opcodeStore_ -> renderExtension + << ".\n" << logofs_flush; + #endif + } + } + break; + case X_QueryFont: + { + // + // Use differential compression at startup and plain + // data compression later. Check X_ListFonts message + // for an explaination. + // + + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_QueryFont); + + if (handleDecodeCached(decodeBuffer, serverCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + // Differential or plain data compression? + decodeBuffer.decodeBoolValue(value); + + if (value) + { + unsigned int numProperties; + unsigned int numCharInfos; + decodeBuffer.decodeValue(numProperties, 16, 8); + decodeBuffer.decodeValue(numCharInfos, 32, 10); + outputLength = 60 + numProperties * 8 + numCharInfos * 12; + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(numProperties, outputMessage + 46, bigEndian_); + PutULONG(numCharInfos, outputMessage + 56, bigEndian_); + handleDecodeCharInfo(decodeBuffer, outputMessage + 8); + handleDecodeCharInfo(decodeBuffer, outputMessage + 24); + decodeBuffer.decodeValue(value, 16, 9); + PutUINT(value, outputMessage + 40, bigEndian_); + decodeBuffer.decodeValue(value, 16, 9); + PutUINT(value, outputMessage + 42, bigEndian_); + decodeBuffer.decodeValue(value, 16, 9); + PutUINT(value, outputMessage + 44, bigEndian_); + decodeBuffer.decodeBoolValue(value); + outputMessage[48] = (unsigned char) value; + decodeBuffer.decodeValue(value, 8); + outputMessage[49] = (unsigned char) value; + decodeBuffer.decodeValue(value, 8); + outputMessage[50] = (unsigned char) value; + decodeBuffer.decodeBoolValue(value); + outputMessage[51] = (unsigned char) value; + decodeBuffer.decodeValue(value, 16, 9); + PutUINT(value, outputMessage + 52, bigEndian_); + decodeBuffer.decodeValue(value, 16, 9); + PutUINT(value, outputMessage + 54, bigEndian_); + unsigned char *nextDest = outputMessage + 60; + decodeBuffer.decodeBoolValue(value); + + int end = 0; + + if (value == 1) + { + unsigned int index; + decodeBuffer.decodeValue(index, 4); + unsigned int length; + const unsigned char *data; + ServerCache::queryFontFontCache.get(index, length, data); + memcpy(nextDest, data, length); + + end = 1; + } + + if (end == 0) + { + unsigned char *saveDest = nextDest; + unsigned int length = numProperties * 8 + numCharInfos * 12; + for (; numProperties; numProperties--) + { + decodeBuffer.decodeValue(value, 32, 9); + PutULONG(value, nextDest, bigEndian_); + decodeBuffer.decodeValue(value, 32, 9); + PutULONG(value, nextDest + 4, bigEndian_); + nextDest += 8; + } + for (; numCharInfos; numCharInfos--) + { + handleDecodeCharInfo(decodeBuffer, nextDest); + + nextDest += 12; + } + ServerCache::queryFontFontCache.set(length, saveDest); + } + + handleSave(messageStore, outputMessage, outputLength); + } + else + { + // Reply length. + unsigned int replyLength; + decodeBuffer.decodeValue(replyLength, 32, 16); + outputLength = 32 + (replyLength << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + + const unsigned char *compressedData = NULL; + unsigned int compressedDataSize = 0; + + int decompressed = handleDecompress(decodeBuffer, requestOpcode, messageStore -> dataOffset, + outputMessage, outputLength, compressedData, + compressedDataSize); + if (decompressed < 0) + { + return -1; + } + else if (decompressed > 0) + { + handleSave(messageStore, outputMessage, outputLength, + compressedData, compressedDataSize); + } + else + { + handleSave(messageStore, outputMessage, outputLength); + } + } + } + break; + case X_QueryPointer: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeBoolValue(value); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> queryPointerRootCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> queryPointerChildCache, 9); + PutULONG(value, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyRootXCache, 8); + serverCache_ -> motionNotifyLastRootX += value; + PutUINT(serverCache_ -> motionNotifyLastRootX, outputMessage + 16, + bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyRootYCache, 8); + serverCache_ -> motionNotifyLastRootY += value; + PutUINT(serverCache_ -> motionNotifyLastRootY, outputMessage + 18, + bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyEventXCache, 8); + PutUINT(serverCache_ -> motionNotifyLastRootX + value, + outputMessage + 20, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyEventYCache, 8); + PutUINT(serverCache_ -> motionNotifyLastRootY + value, + outputMessage + 22, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyStateCache); + PutUINT(value, outputMessage + 24, bigEndian_); + } + break; + case X_QueryTree: + { + unsigned int children; + decodeBuffer.decodeValue(children, 16, 8); + + outputLength = 32 + (children << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + + PutULONG(outputLength, outputMessage + 4, bigEndian_); + + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> queryTreeWindowCache); + + PutULONG(value, outputMessage + 8, bigEndian_); + + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> queryTreeWindowCache); + + PutULONG(value, outputMessage + 12, bigEndian_); + + unsigned char *next = outputMessage + 32; + + PutUINT(children, outputMessage + 16, bigEndian_); + + for (unsigned int i = 0; i < children; i++) + { + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> queryTreeWindowCache); + + PutULONG(value, next + (i * 4), bigEndian_); + } + } + break; + case X_TranslateCoords: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeBoolValue(value); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> translateCoordsChildCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> translateCoordsXCache, 8); + PutUINT(value, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> translateCoordsYCache, 8); + PutUINT(value, outputMessage + 14, bigEndian_); + } + break; + case X_GetImage: + { + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_GetImage); + + if (handleDecodeCached(decodeBuffer, serverCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + // Depth. + decodeBuffer.decodeCachedValue(cValue, 8, + serverCache_ -> depthCache); + // Reply length. + unsigned int replyLength; + decodeBuffer.decodeValue(replyLength, 32, 9); + outputLength = 32 + (replyLength << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + outputMessage[1] = (unsigned char) cValue; + // Visual. + unsigned int visual; + decodeBuffer.decodeCachedValue(visual, 29, + serverCache_ -> visualCache); + PutULONG(visual, outputMessage + 8, bigEndian_); + + // Since ProtoStep8 (#issue 108) + handleCopy(decodeBuffer, requestOpcode, messageStore -> + dataOffset, outputMessage, outputLength); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_GetPointerMapping: + { + unsigned int nextByte; + decodeBuffer.decodeValue(nextByte, 8, 4); + unsigned int replyLength; + decodeBuffer.decodeValue(replyLength, 32, 4); + outputLength = 32 + (replyLength << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + outputMessage[1] = (unsigned char) nextByte; + unsigned char *nextDest = outputMessage + 32; + for (unsigned int i = 32; i < outputLength; i++) + { + decodeBuffer.decodeValue(nextByte, 8, 4); + *nextDest++ = (unsigned char) nextByte; + } + } + break; + case X_GetKeyboardControl: + { + unsigned int nextByte; + decodeBuffer.decodeValue(nextByte, 8, 2); + unsigned int replyLength; + decodeBuffer.decodeValue(replyLength, 32, 8); + outputLength = 32 + (replyLength << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + outputMessage[1] = (unsigned char) nextByte; + unsigned char *nextDest = outputMessage + 8; + for (unsigned int i = 8; i < outputLength; i++) + { + decodeBuffer.decodeValue(nextByte, 8, 4); + *nextDest++ = (unsigned char) nextByte; + } + } + break; + default: + { + if (requestOpcode == opcodeStore_ -> getUnpackParameters) + { + #ifdef TEST + *logofs << "handleWrite: Received get unpack parameters reply " + << "OPCODE#" << (unsigned int) opcodeStore_ -> getUnpackParameters + << ".\n" << logofs_flush; + #endif + + outputLength = 32 + PACK_METHOD_LIMIT; + + outputMessage = writeBuffer_.addMessage(outputLength); + + unsigned int method; + + // + // Let agent use only the unpack methods + // implemented at both sides. + // + + for (int i = 0; i < PACK_METHOD_LIMIT; i++) + { + decodeBuffer.decodeBoolValue(method); + + control -> RemoteUnpackMethods[i] = method; + + *(outputMessage + 32 + i) = + (control -> LocalUnpackMethods[i] == 1 && + method == 1); + } + } + else if (requestOpcode == opcodeStore_ -> getShmemParameters) + { + if (handleShmemReply(decodeBuffer, requestOpcode, + outputMessage, outputLength) < 0) + { + return -1; + } + } + else if (requestOpcode == opcodeStore_ -> getFontParameters) + { + if (handleFontReply(decodeBuffer, requestOpcode, + outputMessage, outputLength) < 0) + { + return -1; + } + } + else + { + #ifdef PANIC + *logofs << "handleWrite: PANIC! No matching request for " + << "reply with sequence number " << sequenceNum + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": No matching request for " + << "reply with sequence number " << sequenceNum + << ".\n"; + + return -1; + } + } + } + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleWrite: Handled reply to OPCODE#" + << (unsigned) requestOpcode << " (" << DumpOpcode(requestOpcode) + << ")" << " for FD#" << fd_ << " with sequence " << serverSequence_ + << ". Output size is " << outputLength << ".\n" << logofs_flush; + #endif + + statistics -> addRepliedRequest(requestOpcode); + } + else // End of if (sequenceQueue_.peek() && ...) + { + // + // Reply didn't match any request opcode. + // Check again if differential encoding + // is disabled. + // + + #ifdef DEBUG + *logofs << "handleWrite: Identified generic reply.\n" + << logofs_flush; + #endif + + requestOpcode = X_Reply; + + if (control -> RemoteDeltaCompression == 0) + { + int result = handleFastWriteReply(decodeBuffer, requestOpcode, + outputMessage, outputLength); + if (result < 0) + { + return -1; + } + else if (result > 0) + { + continue; + } + } + + // + // All replies whose opcode is not pushed in + // sequence number queue are cached together. + // Among such replies are those to extension + // requests. + // + + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_NXInternalGenericReply); + + handleDecode(decodeBuffer, serverCache_, messageStore, + requestOpcode, outputMessage, outputLength); + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleWrite: Handled generic reply for FD#" << fd_ + << " with sequence " << serverSequence_ << ". Output size is " + << outputLength << ".\n" << logofs_flush; + #endif + + statistics -> addRepliedRequest(requestOpcode); + + } // End of if (sequenceQueue_.peek() && ...) else ... + + // + // If any output was produced then write opcode, + // sequence number and size to the buffer. + // + + if (outputLength > 0) + { + *outputMessage = outputOpcode; + + PutUINT(serverSequence_, outputMessage + 2, bigEndian_); + + PutULONG((outputLength - 32) >> 2, outputMessage + 4, bigEndian_); + } + + } // End of if (outputOpcode == 1)... + else + { + // + // It's an event or error. + // + + unsigned int sequenceNum; + unsigned int sequenceDiff; + + decodeBuffer.decodeCachedValue(sequenceDiff, 16, + serverCache_ -> eventSequenceCache, 7); + + sequenceNum = (serverSequence_ + sequenceDiff) & 0xffff; + + serverSequence_ = sequenceNum; + + #ifdef DEBUG + *logofs << "handleWrite: Last server sequence number for FD#" + << fd_ << " is " << serverSequence_ << " with " + << "difference " << sequenceDiff << ".\n" + << logofs_flush; + #endif + + // + // Check if this is an error that matches + // a sequence number for which we were + // expecting a reply. + // + + if (outputOpcode == X_Error) + { + unsigned short int errorSequenceNum; + unsigned char errorOpcode; + + if (sequenceQueue_.peek(errorSequenceNum, errorOpcode) && + ((unsigned) errorSequenceNum == serverSequence_)) + { + // + // Remove the queued sequence of the reply. + // + + #ifdef TEST + *logofs << "handleWrite: WARNING! Removing reply to OPCODE#" + << (unsigned) errorOpcode << " sequence " + << errorSequenceNum << " for FD#" << fd_ + << " due to error.\n" << logofs_flush; + #endif + + sequenceQueue_.pop(errorSequenceNum, errorOpcode); + + // + // Send to the client the current sequence + // number, not the number that matched the + // reply. Because we are generating replies + // at our side, Xlib can incur in a sequence + // lost if the error comes after the auto- + // generated reply. + // + + if (control -> SessionMode == session_proxy) + { + #ifdef TEST + *logofs << "handleWrite: Updating last event's sequence " + << lastSequence_ << " to X server's error sequence " + << "number " << serverSequence_ << " for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + lastSequence_ = serverSequence_; + } + } + + // + // In case of errors always send to client the + // original X server's sequence associated to + // the failing request. + // + + if (control -> SessionMode != session_proxy) + { + #ifdef TEST + *logofs << "handleWrite: Updating last event's sequence " + << lastSequence_ << " to X server's error sequence " + << "number " << serverSequence_ << " for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + lastSequence_ = serverSequence_; + } + } + + // + // Check if by producing events at client side we + // have modified the events' sequence numbering. + // In this case taint the original sequence to + // comply with the last one known by client. + // + +/* +FIXME: Recover the sequence number if the proxy + is not connected to an agent. +*/ + if (serverSequence_ > lastSequence_ || + control -> SessionMode != session_proxy) + { + #ifdef DEBUG + *logofs << "handleWrite: Updating last event's sequence " + << lastSequence_ << " to X server's sequence number " + << serverSequence_ << " for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + lastSequence_ = serverSequence_; + } + #ifdef DEBUG + else if (serverSequence_ < lastSequence_) + { + // + // Use our last auto-generated sequence. + // + + *logofs << "handleWrite: Tainting sequence number " + << serverSequence_ << " to last event's sequence " + << lastSequence_ << " for FD#" << fd_ << ".\n" + << logofs_flush; + } + #endif + + // + // Check if remote side used fast encoding. + // + + if (control -> RemoteDeltaCompression == 0) + { + int result = handleFastWriteEvent(decodeBuffer, outputOpcode, + outputMessage, outputLength); + if (result < 0) + { + return -1; + } + else if (result > 0) + { + continue; + } + } + + // + // Make space for message in the outgoing buffer + // and write opcode and sequence number. + // + + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + + *outputMessage = outputOpcode; + + PutUINT(lastSequence_, outputMessage + 2, bigEndian_); + + #ifdef DEBUG + *logofs << "handleWrite: Going to handle event or error OPCODE#" + << (unsigned int) outputOpcode << " for FD#" << fd_ + << " sequence " << lastSequence_ << " (real was " + << serverSequence_ << ").\n" << logofs_flush; + #endif + + switch (outputOpcode) + { + case X_Error: + { + unsigned char code; + decodeBuffer.decodeCachedValue(code, 8, + serverCache_ -> errorCodeCache); + outputMessage[1] = code; + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleWrite: Handled error ERR_CODE#" + << (unsigned int) code << " for FD#" << fd_; + #endif + + if ((code != 11) && (code != 8) && + (code != 15) && (code != 1)) + { + decodeBuffer.decodeValue(value, 32, 16); + PutULONG(value, outputMessage + 4, bigEndian_); + + #if defined(TEST) || defined(OPCODES) + *logofs << " RES_ID#" << value; + #endif + } + + if (code >= 18) + { + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> errorMinorCache); + PutUINT(value, outputMessage + 8, bigEndian_); + + #if defined(TEST) || defined(OPCODES) + *logofs << " MIN_OP#" << value; + #endif + } + + decodeBuffer.decodeCachedValue(cValue, 8, + serverCache_ -> errorMajorCache); + outputMessage[10] = cValue; + + #if defined(TEST) || defined(OPCODES) + *logofs << " MAJ_OP#" << (unsigned int) cValue; + #endif + + if (code >= 18) + { + unsigned char *nextDest = outputMessage + 11; + for (unsigned int i = 11; i < 32; i++) + { + decodeBuffer.decodeValue(value, 8); + *nextDest++ = (unsigned char) cValue; + } + } + + #if defined(TEST) || defined(OPCODES) + *logofs << " sequence " << lastSequence_ << " (real was " + << serverSequence_ << ") . Size is " + << (unsigned int) outputLength << ".\n" + << logofs_flush; + #endif + } + break; + case ButtonPress: + case ButtonRelease: + case KeyPress: + case KeyRelease: + case MotionNotify: + case EnterNotify: + case LeaveNotify: + { + if (outputOpcode == MotionNotify) + { + decodeBuffer.decodeBoolValue(value); + } + else if (outputOpcode == EnterNotify || outputOpcode == LeaveNotify) + { + decodeBuffer.decodeValue(value, 3); + } + else if (outputOpcode == KeyRelease) + { + decodeBuffer.decodeBoolValue(value); + if (value) + { + value = serverCache_ -> keyPressLastKey; + } + else + { + decodeBuffer.decodeValue(value, 8); + } + } + else if (outputOpcode == ButtonPress || outputOpcode == ButtonRelease) + { + decodeBuffer.decodeCachedValue(cValue, 8, + serverCache_ -> buttonCache); + value = (unsigned int) cValue; + } + else + { + decodeBuffer.decodeValue(value, 8); + } + + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeCachedValue(value, 32, + serverCache_ -> motionNotifyTimestampCache, 9); + serverCache_ -> lastTimestamp += value; + PutULONG(serverCache_ -> lastTimestamp, outputMessage + 4, + bigEndian_); + unsigned char *nextDest = outputMessage + 8; + int skipRest = 0; + if (outputOpcode == KeyRelease) + { + decodeBuffer.decodeBoolValue(value); + if (value) + { + for (unsigned int i = 0; i < 23; i++) + { + *nextDest++ = serverCache_ -> keyPressCache[i]; + } + skipRest = 1; + } + } + + if (!skipRest) + { + for (unsigned int i = 0; i < 3; i++) + { + decodeBuffer.decodeCachedValue(value, 29, + *serverCache_ -> motionNotifyWindowCache[i], 6); + PutULONG(value, nextDest, bigEndian_); + nextDest += 4; + } + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyRootXCache, 6); + serverCache_ -> motionNotifyLastRootX += value; + PutUINT(serverCache_ -> motionNotifyLastRootX, outputMessage + 20, + bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyRootYCache, 6); + serverCache_ -> motionNotifyLastRootY += value; + PutUINT(serverCache_ -> motionNotifyLastRootY, outputMessage + 22, + bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyEventXCache, 6); + PutUINT(serverCache_ -> motionNotifyLastRootX + value, + outputMessage + 24, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyEventYCache, 6); + PutUINT(serverCache_ -> motionNotifyLastRootY + value, + outputMessage + 26, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> motionNotifyStateCache); + PutUINT(value, outputMessage + 28, bigEndian_); + if (outputOpcode == EnterNotify || outputOpcode == LeaveNotify) + { + decodeBuffer.decodeValue(value, 2); + } + else + { + decodeBuffer.decodeBoolValue(value); + } + outputMessage[30] = (unsigned char) value; + if (outputOpcode == EnterNotify || outputOpcode == LeaveNotify) + { + decodeBuffer.decodeValue(value, 2); + outputMessage[31] = (unsigned char) value; + } + else if (outputOpcode == KeyPress) + { + serverCache_ -> keyPressLastKey = outputMessage[1]; + for (unsigned int i = 8; i < 31; i++) + { + serverCache_ -> keyPressCache[i - 8] = outputMessage[i]; + } + } + } + } + break; + case ColormapNotify: + { + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> colormapNotifyWindowCache, 8); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> colormapNotifyColormapCache, 8); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeBoolValue(value); + outputMessage[12] = (unsigned char) value; + decodeBuffer.decodeBoolValue(value); + outputMessage[13] = (unsigned char) value; + } + break; + case ConfigureNotify: + { + unsigned char *nextDest = outputMessage + 4; + for (unsigned int i = 0; i < 3; i++) + { + decodeBuffer.decodeCachedValue(value, 29, + *serverCache_ -> configureNotifyWindowCache[i], 9); + PutULONG(value, nextDest, bigEndian_); + nextDest += 4; + } + for (unsigned int j = 0; j < 5; j++) + { + decodeBuffer.decodeCachedValue(value, 16, + *serverCache_ -> configureNotifyGeomCache[j], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + decodeBuffer.decodeBoolValue(value); + *nextDest = value; + } + break; + case CreateNotify: + { + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> createNotifyWindowCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeValue(value, 29, 5); + serverCache_ -> createNotifyLastWindow += value; + serverCache_ -> createNotifyLastWindow &= 0x1fffffff; + PutULONG(serverCache_ -> createNotifyLastWindow, outputMessage + 8, + bigEndian_); + unsigned char* nextDest = outputMessage + 12; + for (unsigned int i = 0; i < 5; i++) + { + decodeBuffer.decodeValue(value, 16, 9); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + decodeBuffer.decodeBoolValue(value); + *nextDest = (unsigned char) value; + } + break; + case Expose: + { + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> exposeWindowCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned char *nextDest = outputMessage + 8; + for (unsigned int i = 0; i < 5; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *serverCache_ -> exposeGeomCache[i], 6); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + } + break; + case FocusIn: + case FocusOut: + { + decodeBuffer.decodeValue(value, 3); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> focusInWindowCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeValue(value, 2); + outputMessage[8] = (unsigned char) value; + } + break; + case KeymapNotify: + { + decodeBuffer.decodeBoolValue(value); + if (value) + memcpy(outputMessage + 1, ServerCache::lastKeymap.getData(), 31); + else + { + unsigned char *nextDest = outputMessage + 1; + for (unsigned int i = 1; i < 32; i++) + { + decodeBuffer.decodeValue(value, 8); + *nextDest++ = (unsigned char) value; + } + ServerCache::lastKeymap.set(31, outputMessage + 1); + } + } + break; + case MapNotify: + case UnmapNotify: + case DestroyNotify: + { + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> mapNotifyEventCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> mapNotifyWindowCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + if (outputOpcode == MapNotify || outputOpcode == UnmapNotify) + { + decodeBuffer.decodeBoolValue(value); + outputMessage[12] = (unsigned char) value; + } + } + break; + case NoExpose: + { + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> noExposeDrawableCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + serverCache_ -> noExposeMinorCache); + PutUINT(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(cValue, 8, + serverCache_ -> noExposeMajorCache); + outputMessage[10] = cValue; + } + break; + case PropertyNotify: + { + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> propertyNotifyWindowCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> propertyNotifyAtomCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeValue(value, 32, 9); + serverCache_ -> lastTimestamp += value; + PutULONG(serverCache_ -> lastTimestamp, outputMessage + 12, + bigEndian_); + decodeBuffer.decodeBoolValue(value); + outputMessage[16] = (unsigned char) value; + } + break; + case ReparentNotify: + { + unsigned char* nextDest = outputMessage + 4; + for (unsigned int i = 0; i < 3; i++) + { + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> reparentNotifyWindowCache, 9); + PutULONG(value, nextDest, bigEndian_); + nextDest += 4; + } + decodeBuffer.decodeValue(value, 16, 6); + PutUINT(value, nextDest, bigEndian_); + decodeBuffer.decodeValue(value, 16, 6); + PutUINT(value, nextDest + 2, bigEndian_); + decodeBuffer.decodeBoolValue(value); + outputMessage[20] = (unsigned char)value; + } + break; + case SelectionClear: + { + decodeBuffer.decodeValue(value, 32, 9); + serverCache_ -> lastTimestamp += value; + PutULONG(serverCache_ -> lastTimestamp, outputMessage + 4, + bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> selectionClearWindowCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> selectionClearAtomCache, 9); + PutULONG(value, outputMessage + 12, bigEndian_); + } + break; + case SelectionRequest: + { + decodeBuffer.decodeValue(value, 32, 9); + serverCache_ -> lastTimestamp += value; + PutULONG(serverCache_ -> lastTimestamp, outputMessage + 4, + bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> selectionClearWindowCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> selectionClearWindowCache, 9); + PutULONG(value, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> selectionClearAtomCache, 9); + PutULONG(value, outputMessage + 16, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> selectionClearAtomCache, 9); + PutULONG(value, outputMessage + 20, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> selectionClearAtomCache, 9); + PutULONG(value, outputMessage + 24, bigEndian_); + } + break; + case VisibilityNotify: + { + decodeBuffer.decodeCachedValue(value, 29, + serverCache_ -> visibilityNotifyWindowCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeValue(value, 2); + outputMessage[8] = (unsigned char) value; + } + break; + default: + { + #ifdef TEST + *logofs << "handleWrite: Using generic event compression " + << "for OPCODE#" << (unsigned int) outputOpcode + << ".\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(*(outputMessage + 1), 8, + serverCache_ -> genericEventCharCache); + + for (unsigned int i = 0; i < 14; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *serverCache_ -> genericEventIntCache[i]); + + PutUINT(value, outputMessage + i * 2 + 4, bigEndian_); + } + } + } // End of switch (outputOpcode)... + + #if defined(TEST) || defined(OPCODES) + if (outputOpcode != X_Error) + { + *logofs << "handleWrite: Handled event OPCODE#" + << (unsigned int) outputOpcode << " for FD#" + << fd_ << " sequence " << lastSequence_ << " (real was " + << serverSequence_ << "). Size is " << outputLength + << ".\n" << logofs_flush; + } + #endif + + // + // Check if we need to suppress the error. + // + + if (outputOpcode == X_Error && + handleTaintSyncError(*(outputMessage + 10)) > 0) + { + #if defined(TEST) || defined(OPCODES) + *logofs << "handleWrite: WARNING! Suppressed error OPCODE#" + << (unsigned int) outputOpcode << " for FD#" + << fd_ << " sequence " << lastSequence_ << ".\n" + << logofs_flush; + #endif + + writeBuffer_.removeMessage(32); + } + + } // End of if (outputOpcode == 1)... else ... + + // + // Check if we produced enough data. We need to + // decode all provided messages. Just update the + // finish flag in case of failure. + // + + handleFlush(flush_if_needed); + + } // End of while (decodeBuffer.decodeOpcodeValue(outputOpcode, 8, ... + + } // End of the decoding block. + + // + // Write any remaining data to the X connection. + // + + if (handleFlush(flush_if_any) < 0) + { + return -1; + } + + return 1; +} + +// +// End of handleWrite(). +// + +// +// Other members. +// + +int ClientChannel::handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, + T_store_action action, int position, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + #if defined(TEST) || defined(SPLIT) + + // Since ProtoStep8 (#issue 108) + *logofs << "handleSplit: PANIC! SPLIT! Split should " + << "not be enabled for message " << "OPCODE#" + << (unsigned int) store -> opcode() << ".\n" + << logofs_flush; + + HandleCleanup(); + + #endif + + // + // Refuse the split if it is not introduced + // by a start split. + // + + // Since ProtoStep7 (#issue 108) + if (splitState_.resource == nothing || enableSplit_ == 0) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Nothing to do for message " + << "OPCODE#" << (unsigned int) store -> opcode() + << " of size " << size << " position " << position + << " with action [" << DumpAction(action) << "] at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeBoolValue(0); + + return 0; + } + + // + // It's not advisable to allocate the store at + // the time we receive the start-split because + // we may process all the splits received and + // deallocate the store even before we receive + // the end split. Another message for the same + // split sequence may then come and we would + // have a null split store. + // + + handleSplitStoreAlloc(&splitResources_, splitState_.resource); + + // + // Check if the split was actually requested by + // the agent and if the request was saved in the + // message store. The split can also be refused + // if the message is smaller than the threshold + // or if the split store is already full. + // + + if (mustSplitMessage(splitState_.resource) == 0) + { + if (action == IS_HIT || canSplitMessage(splitState_.mode, size) == 0) + { + #if defined(TEST) || defined(SPLIT) + + if (splitState_.mode == split_none) + { + #ifdef PANIC + *logofs << "handleSplit: PANIC! SPLIT! Split state has " + << "mode 'none'.\n" << logofs_flush; + #endif + + HandleCleanup(); + } + + if (action != IS_HIT && (int) size >= + control -> SplitDataThreshold) + { + #ifdef WARNING + *logofs << "handleSplit: WARNING! SPLIT! Split stores have " + << clientStore_ -> getSplitTotalSize() << " messages " + << "and " << clientStore_ -> getSplitTotalStorageSize() + << " allocated bytes.\n" << logofs_flush; + #endif + } + + #endif + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Message OPCODE#" + << (unsigned int) store -> opcode() << " of size " << size + << " [not split] with resource " << splitState_.resource + << " mode " << splitState_.mode << " position " << position + << " and action [" << DumpAction(action) << "] at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeBoolValue(0); + + return 0; + } + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Message OPCODE#" + << (unsigned int) store -> opcode() << " of size " << size + << " [split] with resource " << splitState_.resource + << " mode " << splitState_.mode << " position " << position + << " and action [" << DumpAction(action) << "] at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeBoolValue(1); + + T_checksum checksum = NULL; + + if (action == IS_ADDED) + { + checksum = store -> getChecksum(position); + } + else if (action == is_discarded) + { + // + // Generate the checksum on the fly. + // + + checksum = store -> getChecksum(buffer, size, bigEndian_); + } + + // + // The method must abort the connection + // if it can't allocate the split. + // + + Split *splitMessage = clientStore_ -> getSplitStore(splitState_.resource) -> + add(store, splitState_.resource, splitState_.mode, + position, action, checksum, buffer, size); + + // + // Send the checksum. By using the checksum, + // the remote end will try to locate the + // message and load it from disk. + // + + if (action == IS_HIT) + { + splitMessage -> setState(split_loaded); + } + else if (handleSplitChecksum(encodeBuffer, checksum) == 0) + { + // + // If the checksum is not sent, for example + // because loading of messages from disk is + // disabled, then mark the split as missed. + // + + #ifdef WARNING + *logofs << "handleSplit: WARNING! Checksum not sent. " + << "Marking the split as [missed].\n" + << logofs_flush; + #endif + + splitMessage -> setState(split_missed); + } + + if (action == is_discarded) + { + delete [] checksum; + } + + // + // Check if we are ready to send a new split + // for this store. + // + + handleSplitPending(splitState_.resource); + + #if defined(TEST) || defined(SPLIT) + + *logofs << "handleSplit: SPLIT! There are " << clientStore_ -> + getSplitTotalSize() << " messages and " << clientStore_ -> + getSplitTotalStorageSize() << " bytes to send in " + << "the split stores.\n" << logofs_flush; + + clientStore_ -> dumpSplitStore(splitState_.resource); + + #endif + + return 1; +} + +int ClientChannel::handleSplit(EncodeBuffer &encodeBuffer) +{ + // + // Determine the maximum amount of bytes + // we can write in this iteration. + // + + int total = control -> SplitDataPacketLimit; + + int bytes = total; + int splits = 0; + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Handling splits " + << "for FD#" << fd_ << " with " << clientStore_ -> + getSplitTotalSize() << " elements and " << total + << " bytes to write at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + if (proxy -> handleAsyncSwitch(fd_) < 0) + { + return -1; + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Looping to find " + << "if there is any split to send.\n" + << logofs_flush; + #endif + + SplitStore *splitStore; + + Split *splitMessage; + + // + // Divide the available bandwidth among all the active + // split stores by implementing a simple round-robin + // mechanism. This can be extended by using an external + // function returning the number of bytes to be written + // based on the state of the split (splits which didn't + // receive yet a confirmation event could be delayed), + // the current bitrate, and by letting the agent asso- + // ciate a priority to the resource in the start split + // operation. + // + + splitState_.pending = 0; + + splitResources_.rotate(); + + // + // Copy the list since elements can be removed + // in the middle of the loop. + // + + T_list splitList = splitResources_.copyList(); + + for (T_list::iterator j = splitList.begin(); + j != splitList.end(); j++) + { + int resource = *j; + + #ifdef DEBUG + *logofs << "handleSplit: SPLIT! Looping with current " + << "resource " << resource << ".\n" + << logofs_flush; + #endif + + splitStore = clientStore_ -> getSplitStore(resource); + + if (splitStore != NULL) + { + // + // Don't send more than the the packet size + // bytes but ensure that we abort any split + // found in the disk cache. + // + + for (;;) + { + #if defined(TEST) || defined(SPLIT) + + clientStore_ -> dumpSplitStore(resource); + + #endif + + splitMessage = splitStore -> getFirstSplit(); + + if (splitMessage == NULL) + { + // + // We have created the store after a start + // split but no message was added yet. + // + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: WARNING! SPLIT! The split store " + << "is still empty.\n" << logofs_flush; + #endif + + break; + } + + // + // Splits already aborted can't be in the + // split store. + // + + #if defined(TEST) || defined(SPLIT) + + if (splitMessage -> getState() == split_aborted) + { + *logofs << "handleSplit: PANIC! SPLIT! Found an " + << "aborted split in store [" << resource + << "].\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + // + // Check if there are more messages in the + // store that can be aborted or if we have + // exceeded the number of bytes we can send + // for this iteration. + // + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Checking closure " + << "of the inner loop with " << bytes + << " bytes to write and split state [" + << DumpState(splitMessage -> getState()) + << "].\n" << logofs_flush; + #endif + + if ((splitMessage -> getMode() == split_sync && + splitMessage -> getState() == split_added) || + (bytes <= 0 && splitMessage -> + getState() != split_loaded)) + { + break; + } + + // + // If the split was loaded at the remote + // side abort it immediately. + // + + if (splitMessage -> getState() == split_loaded) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Sending more data " + << "for store [" << resource << "] with " + << "a split to be aborted.\n" + << logofs_flush; + #endif + + if (handleSplitSend(encodeBuffer, resource, splits, bytes) < 0) + { + return -1; + } + } + else if (bytes > 0) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Sending more data " + << "for store [" << resource << "] with " + << bytes << " bytes to send.\n" + << logofs_flush; + #endif + + if (handleSplitSend(encodeBuffer, resource, splits, bytes) < 0) + { + return -1; + } + } + + // + // Check if the split store was deleted. + // + + splitStore = clientStore_ -> getSplitStore(resource); + + if (splitStore == NULL) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Exiting from the " + << "inner loop with split store [" << resource + << "] destroyed.\n" << logofs_flush; + #endif + + break; + } + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Completed handling splits " + << "for store [" << resource << "] with " << bytes + << " bytes still to send.\n" << logofs_flush; + #endif + + // + // Check if there is still a split to + // send for the store just processed. + // + + handleSplitPending(resource); + } + } + + #if defined(TEST) || defined(SPLIT) + + if (splits == 0) + { + #ifdef PANIC + *logofs << "handleSplit: PANIC! Function called but " + << "no split message was sent.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } + + *logofs << "handleSplit: SPLIT! Sent " << splits + << " splits and " << total - bytes << " bytes for FD#" << fd_ + << " with " << clientStore_ -> getSplitTotalStorageSize() + << " bytes and [" << clientStore_ -> getSplitTotalSize() + << "] splits remaining.\n" << logofs_flush; + + *logofs << "handleSplit: SPLIT! The pending split flag is " + << splitState_.pending << " with " << clientStore_ -> + getSplitTotalSize() << " splits in the split stores.\n" + << logofs_flush; + + clientStore_ -> dumpSplitStores(); + + #endif + + return 1; +} + +int ClientChannel::handleSplitSend(EncodeBuffer &encodeBuffer, int resource, + int &splits, int &bytes) +{ + #if defined(TEST) || defined(SPLIT) + + SplitStore *splitStore = clientStore_ -> getSplitStore(resource); + + Split *splitMessage = splitStore -> getFirstSplit(); + + if (splitStore -> getResource() != resource || + splitMessage -> getResource() != resource) + { + #ifdef PANIC + *logofs << "handleSplitSend: PANIC! The resource doesn't " + << "match the split store.\n" << logofs_flush; + #endif + + HandleCleanup(); + } + + *logofs << "handleSplitSend: SPLIT! Sending message " + << "OPCODE#" << (unsigned) opcodeStore_ -> splitData + << " for resource " << splitMessage -> getResource() + << " with request " << splitMessage -> getRequest() + << " position " << splitMessage -> getPosition() + << " and " << bytes << " bytes to write.\n" + << logofs_flush; + #endif + + // + // Use a special opcode to signal the other + // side this is part of a split and not a + // new message. + // + + encodeBuffer.encodeOpcodeValue(opcodeStore_ -> splitData, + clientCache_ -> opcodeCache); + + encodeBuffer.encodeCachedValue(resource, 8, + clientCache_ -> resourceCache); + + int result = clientStore_ -> getSplitStore(resource) -> + send(encodeBuffer, bytes); + + if (result < 0) + { + #ifdef PANIC + *logofs << "handleSplit: PANIC! Error sending splits for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Error sending splits for FD#" + << fd_ << ".\n"; + + return -1; + } + + // + // Get the bits written and update the + // statistics for this special opcode. + // + + int bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(SPLIT)|| defined(OPCODES) + *logofs << "handleSplitSend: SPLIT! Handled request OPCODE#" + << (unsigned int) opcodeStore_ -> splitData << " (" + << DumpOpcode(opcodeStore_ -> splitData) << ")" << " for FD#" + << fd_ << " sequence none. 0 bytes in, " << bits << " bits (" + << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; + #endif + + statistics -> addRequestBits(opcodeStore_ -> splitData, 0, bits); + + bytes -= bits >> 3; + + splits++; + + if (result == 1) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitSend: SPLIT! Split at the head " + << "of the list was completely transferred.\n" + << logofs_flush; + #endif + + // + // The split at the head of the list was + // completely transferred. + // + + handleRestart(sequence_deferred, resource); + } + #if defined(TEST) || defined(SPLIT) + else + { + *logofs << "handleSplitSend: SPLIT! More data to send " + << "for the split at the head of the list.\n" + << logofs_flush; + } + #endif + + return result; +} + +int ClientChannel::handleSplitChecksum(EncodeBuffer &encodeBuffer, T_checksum checksum) +{ + // + // Send the checksum only if the loading + // or the saving of the message to the + // persistent image cache is enabled. + // + + if ((control -> ImageCacheEnableLoad == 1 || + control -> ImageCacheEnableSave == 1) && + (enableLoad_ == 1 || enableSave_ == 1)) + { + encodeBuffer.encodeBoolValue(1); + + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + encodeBuffer.encodeValue((unsigned int) checksum[i], 8); + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitChecksum: SPLIT! Sent checksum " + << "[" << DumpChecksum(checksum) << "].\n" + << logofs_flush; + #endif + + return 1; + } + else + { + encodeBuffer.encodeBoolValue(0); + + return 0; + } +} + +void ClientChannel::handleSplitPending() +{ + #if defined(TEST) || defined(SPLIT) + + int previous = splitState_.pending; + + #endif + + if (clientStore_ -> getSplitTotalSize() == 0) + { + splitState_.pending = 0; + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitPending: SPLIT! Set the pending " + << "split flag to " << splitState_.pending + << " with split stores empty.\n" + << logofs_flush; + #endif + } + else + { + // + // Loop through the stores to find if + // there is any split that has become + // ready. + // + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitPending: WARNING! SPLIT! Looping to " + << "find if there is any split pending.\n" + << logofs_flush; + #endif + + splitState_.pending = 0; + + T_list &splitList = splitResources_.getList(); + + for (T_list::iterator j = splitList.begin(); + j != splitList.end(); j++) + { + int resource = *j; + + SplitStore *splitStore = clientStore_ -> getSplitStore(resource); + + if (splitStore != NULL) + { + #if defined(TEST) || defined(SPLIT) + + clientStore_ -> dumpSplitStore(resource); + + #endif + + Split *splitMessage = splitStore -> getFirstSplit(); + + if (splitMessage != NULL && canSendSplit(splitMessage) == 1) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitPending: SPLIT! Found a pending " + << "split in store [" << resource << "].\n" + << logofs_flush; + #endif + + splitState_.pending = 1; + + #if defined(TEST) || defined(SPLIT) + + if (splitMessage -> getState() == split_loaded) + { + *logofs << "handleSplitPending: PANIC! SPLIT! Found a " + << "loaded split in store [" << resource + << "].\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + break; + } + } + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitPending: SPLIT! Set the pending " + << "split flag to " << splitState_.pending + << " with " << clientStore_ -> getSplitTotalSize() + << " splits in the split stores.\n" + << logofs_flush; + #endif + } + + #if defined(TEST) || defined(SPLIT) + + if (splitState_.pending != previous) + { + *logofs << "handleSplitPending: SPLIT! Pending state " + << "changed from " << previous << " to " + << splitState_.pending << ".\n" + << logofs_flush; + } + + #endif +} + +int ClientChannel::handleSplitEvent(EncodeBuffer &encodeBuffer, Split *splitMessage) +{ + SplitStore *splitStore; + + int resource = splitMessage -> getResource(); + + #if defined(TEST) || defined(INFO) + + splitStore = clientStore_ -> getSplitStore(resource); + + if (splitStore == NULL) + { + #ifdef PANIC + *logofs << "handleSplitEvent: PANIC! The split store can't " + << "be NULL handling abort splits.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } + else if (splitMessage -> getState() != split_loaded) + { + *logofs << "handleSplitEvent: PANIC! Can't find the split " + << "to be aborted.\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + // + // Send any split that it is possible to + // abort until the store is either empty + // or the next split can't be aborted. + // + + if (proxy -> handleAsyncSwitch(fd_) < 0) + { + return -1; + } + + while ((splitStore = clientStore_ -> + getSplitStore(resource)) != NULL && + (splitMessage = splitStore -> getFirstSplit()) != NULL && + splitMessage -> getState() == split_loaded) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitEvent: SPLIT! Aborting split with " + << "checksum [" << DumpChecksum(splitMessage -> + getChecksum()) << "] for resource " << resource + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + int any = 0; + + if (handleSplitSend(encodeBuffer, resource, any, any) < 0) + { + return -1; + } + } + + #if defined(TEST) || defined(SPLIT) + + if ((splitStore = clientStore_ -> + getSplitStore(resource)) == NULL) + { + *logofs << "handleSplitEvent: SPLIT! The split store [" + << resource << "] has been destroyed.\n" + << logofs_flush; + } + else if ((splitMessage = splitStore -> + getFirstSplit()) == NULL) + { + *logofs << "handleSplitEvent: SPLIT! The split store [" + << resource << "] is empty.\n" + << logofs_flush; + } + else if (splitMessage -> getState() != split_loaded) + { + *logofs << "handleSplitEvent: SPLIT! The split at the " + << "head of store [" << resource << "] doesn't " + << "need to be aborted.\n" << logofs_flush; + } + + #endif + + return 1; +} + +int ClientChannel::handleSplitEvent(DecodeBuffer &decodeBuffer) +{ + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitEvent: SPLIT! Handling abort " + << "split messages for FD#" << fd_ << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + // Since ProtoStep7 (#issue 108) + + // + // Decode the information about the + // message to be updated. + // + + unsigned char resource; + + decodeBuffer.decodeCachedValue(resource, 8, + serverCache_ -> resourceCache); + + unsigned int loaded; + + decodeBuffer.decodeBoolValue(loaded); + + unsigned char request; + unsigned int size; + + if (loaded == 1) + { + decodeBuffer.decodeOpcodeValue(request, serverCache_ -> abortOpcodeCache); + + decodeBuffer.decodeValue(size, 32, 14); + } + else + { + request = 0; + size = 0; + } + + unsigned int value; + + md5_byte_t checksum[MD5_LENGTH]; + + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + decodeBuffer.decodeValue(value, 8); + + checksum[i] = (unsigned char) value; + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitEvent: SPLIT! Checking split " + << "with checksum [" << DumpChecksum(checksum) + << "] loaded " << loaded << " request " << (unsigned int) + request << " compressed size " << size << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + Split *splitMessage = handleSplitFind(checksum, resource); + + if (splitMessage != NULL) + { + if (loaded == 1) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitEvent: SPLIT! Marked split with " + << "checksum [" << DumpChecksum(checksum) << "] " + << "as [loaded] at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + splitMessage -> setState(split_loaded); + + #if defined(TEST) || defined(SPLIT) + + if (splitMessage -> compressedSize() != (int) size) + { + *logofs << "handleSplitEvent: WARNING! SPLIT! Updating " + << "compressed data size from " << splitMessage -> + compressedSize() << " to " << size << ".\n" + << logofs_flush; + } + + #endif + + splitMessage -> compressedSize(size); + + // + // The splits to be aborted are checked by the split + // store at the time we are going to send a new chunk + // of split data. The splits must be strictly handled + // in the same order as they were added to the split + // store and the split we want to abort here may be + // not at the head of the list. + // + + if (splitMessage == clientStore_ -> + getSplitStore(resource) -> getFirstSplit()) + { + // + // We don't need to flush this packet immediately. + // The abort can be sent at any time to the remote + // proxy. What's important is that we restart the + // agent resource as soon as possible. + // + + #if defined(TEST) || defined(SPLIT) + + T_timestamp startTs = getTimestamp(); + + *logofs << "handleSplitEvent: SPLIT! Encoding abort " + << "split events for FD#" << fd_ << " with " + << "resource " << (unsigned) resource << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + if (proxy -> handleAsyncSplit(fd_, splitMessage) < 0) + { + return -1; + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitEvent: SPLIT! Spent " + << diffTimestamp(startTs, getTimestamp()) << " Ms " + << "handling abort split events for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + // + // Check if we can clear the pending flag. + // + + handleSplitPending(); + } + #if defined(TEST) || defined(SPLIT) + else + { + *logofs << "handleSplitEvent: WARNING! SPLIT! Abort split " + << "event not sent because not at the head " + << "of the list.\n" << logofs_flush; + } + #endif + } + else + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitEvent: SPLIT! Marked split with " + << "checksum [" << DumpChecksum(checksum) << "] " + << "as [missed] at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + splitMessage -> setState(split_missed); + + // + // Check if we can set the pending flag. + // + + handleSplitPending(resource); + } + } + else + { + // + // The split report came after the split was already + // sent or the split store deleted. If the message + // had been loaded from disk by the remote side, we + // need to update the compressed size in our message + // store or the checksum will not match at the time + // we will try to save the message store on disk. + // + + if (loaded == 1 && size != 0) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitEvent: WARNING! SPLIT! Can't find " + << "the split. Updating in the message store.\n" + << logofs_flush; + #endif + + MessageStore *store = clientStore_ -> getRequestStore(request); + + if (store != NULL) + { + store -> updateData(checksum, size); + } + #if defined(TEST) || defined(SPLIT) + else + { + #ifdef PANIC + *logofs << "handleSplitEvent: PANIC! The message store " + << "can't be null.\n" << logofs_flush; + #endif + + HandleCleanup(); + } + #endif + } + #if defined(TEST) || defined(SPLIT) + else + { + *logofs << "handleSplitEvent: WARNING! SPLIT! No need to " + << "update the store with loaded " << loaded + << " and compressed size " << size << ".\n" + << logofs_flush; + } + #endif + } + + return 1; +} + +Split *ClientChannel::handleSplitFind(T_checksum checksum, int resource) +{ + // + // It can be that we handled all the splits, + // restarted the resource and deleted the + // store before the event could even reach + // our side. + // + + SplitStore *splitStore = clientStore_ -> getSplitStore(resource); + + if (splitStore != NULL) + { + Split *splitMessage; + + T_splits *splitList = splitStore -> getSplits(); + + for (T_splits::iterator i = splitList -> begin(); + i != splitList -> end(); i++) + { + splitMessage = (*i); + + if (splitMessage -> getChecksum() != NULL) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitFind: SPLIT! Comparing with message [" + << DumpChecksum(splitMessage -> getChecksum()) + << "].\n" << logofs_flush; + #endif + + if (memcmp(checksum, splitMessage -> getChecksum(), MD5_LENGTH) == 0) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitFind: SPLIT! Located split for " + << "checksum [" << DumpChecksum(checksum) << "] " + << "in store [" << splitStore -> getResource() + << "].\n" << logofs_flush; + #endif + + return splitMessage; + } + } + } + } + #if defined(TEST) || defined(SPLIT) + else + { + *logofs << "handleSplitFind: WARNING! SPLIT! The split store " + << "was already deleted.\n" << logofs_flush; + } + #endif + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitFind: WARNING! SPLIT! Can't find the " + << "split for checksum [" << DumpChecksum(checksum) + << "].\n" << logofs_flush; + #endif + + return NULL; +} + +int ClientChannel::handleRestart(T_sequence_mode mode, int resource) +{ + // + // The agent must send a start-split message, followed by the + // X messages that may be optionally split by the proxy. Usu- + // ally, in the middle of a start-split/end-split sequence is + // a single PutImage() or PutPackedImage(), that, in turn, + // can generate multiple partial requests, like a SetUnpack- + // Colormap() and SetUnpackAlpha() followed by the image that + // must be transferred. Multiple requests may be also genera- + // ted because the maximum size of a X request has been exce- + // eded, so that Xlib has divided the single image in multi- + // ple sub-image requests. The agent doesn't need to take care + // of that, except tracking the result of the split operation. + // + // By monitoring the notify events sent by the proxy, the + // agent will have to implement its own strategy to deal with + // its resources (for example its clients). For example: + // + // - It will issue a new image request and suspend a client + // if the image was not entirely sent in the main X oputput + // stream. + // + // - It will choose to commit or discard the messages after + // they are recomposed at the remote side. The set of mes- + // sages that will have to be committed will include all + // messages that were part of the split (the colormap, the + // alpha channel). + // + // - It will restart its own client, in the case it had been + // suspended. + // + // A more useful strategy would be to replace the original im- + // age with a tiny 'placeholder' if a split took place, and + // synchronize the content of the drawable at later time. This + // is generally referred as 'lazy encoding'. + // + // The agent will be able to identify the original split ope- + // ration (the one marked with the start-spit) by the small + // integer number (0-255) referred to as the 'resource' field. + // + // Before the proxy will be able to report the status of the + // split, the agent will have to close the sequence by issueing + // an end-split. The proxy will then report the result of the + // operation, so that the agent will have the option of suspend- + // ing the client or marking the drawable as dirty and take + // care of synchronizing it at later time. + // + // One of the following cases may be encountered: + // + // notify_no_split: All messages were sent in the main out- + // put stream, so that no split actually + // took place. + // + // notify_start_split: One or more messages were split, so, + // at discrection of the agent, the client + // may be suspended until the transferral + // is completed. + // + // notify_commit_split: One of the requests that made up the + // split was recomposed. The agent should + // either commit the given request or tell + // the proxy to discard it. + // + // notify_end_split: The split was duly completed. The agent + // can restart the client. + // + // notify_empty_split: No more split operation are pending. + // The agent can use this information to + // implement specific strategies requiring + // that all messages have been recomposed + // at the remote end, like updating the + // drawables that were not synchronized + // because of the lazy encoding. + // + // By checking the split and commit store we can determine if we + // need to send a new notification event to the agent. There can + // be four different cases: + // + // - If the split store is not null and not empty, we are still + // in the middle of a split. + // + // - If the commit store is not empty, we completely recomposed + // a full message and can send a new commit notify. + // + // - If the split store has become empty, we recomposed all the + // messages added for the given resource, and so will be able + // to restart the resource. + // + // - If no more messages are in the split stores, we can notify + // an empty split event to the agent. + // + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleRestart: SPLIT! Handling [" + << (mode == sequence_immediate ? "immediate" : "deferred") + << "] restart events for resource " << resource << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + SplitStore *splitStore = clientStore_ -> getSplitStore(resource); + + if (mode == sequence_immediate) + { + // + // We have received an end-split request. If the store + // was not deleted already, we mark the last split added + // as the one ending the row for this resource. If the + // commit() function returns 0 it means that the split + // store is either empty or that we did not add any split + // for this resource. This is because when connected to + // an old proxy version we only have a single store for + // all the resources. + // + // It can happen that all the split messages that were + // originally appended to the list were completely sent + // before our client had the chance of ending the split + // sequence. In this case the split store will be empty + // or already deleted and so we will be able to restart + // the resource. + // + + #if defined(TEST) || defined(SPLIT) + + if (splitStore == NULL) + { + *logofs << "handleRestart: WARNING! SPLIT! Split store [" + << resource << "] was already deleted.\n" + << logofs_flush; + } + else + { + clientStore_ -> dumpSplitStore(resource); + } + + #endif + + if (splitStore == NULL || splitStore -> getSize() == 0) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleRestart: SPLIT! Immediate agent split event " + << "TYPE#" << (unsigned) opcodeStore_ -> noSplitNotify + << " [no split] with resource " << resource + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + if (handleNotify(notify_no_split, sequence_immediate, + resource, nothing, nothing) < 0) + { + return -1; + } + } + else + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleRestart: SPLIT! Immediate agent split event " + << "TYPE#" << (unsigned) opcodeStore_ -> startSplitNotify + << " [start split] with resource " << resource + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + if (handleNotify(notify_start_split, sequence_immediate, + resource, nothing, nothing) < 0) + { + return -1; + } + } + } + else + { + // + // We have completely transferred a message + // that was put in the split store. + // + // The id of the resource can be different + // than the index of the store if we are + // connected to an old proxy. + // + + #if defined(TEST) || defined(SPLIT) + + if (splitStore == NULL) + { + #ifdef PANIC + *logofs << "handleRestart: PANIC! The split store can't " + << "be NULL handling deferred restart events.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } + else + { + clientStore_ -> dumpSplitStore(resource); + } + + #endif + + CommitStore *commitStore = clientStore_ -> getCommitStore(); + + #if defined(TEST) || defined(SPLIT) + + clientStore_ -> dumpCommitStore(); + + #endif + + // + // Check if there is any commit to notify. + // + + Split *split; + + T_splits *commitList = commitStore -> getSplits(); + + for (T_splits::iterator i = commitList -> begin(); + i != commitList -> end(); i++) + { + split = *i; + + if (split -> getState() != split_notified) + { + #if defined(TEST) || defined(SPLIT) + + if (split -> getResource() != resource) + { + #ifdef PANIC + *logofs << "handleSplitSend: PANIC! The resource doesn't " + << "match the split store.\n" << logofs_flush; + #endif + + HandleCleanup(); + } + + #endif + + int request = split -> getRequest(); + int position = split -> getPosition(); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleRestart: SPLIT! Deferred agent split event " + << "TYPE#" << (unsigned) opcodeStore_ -> commitSplitNotify + << " [commit split] with resource " << resource << " request " + << request << " position " << position << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + if (handleNotify(notify_commit_split, sequence_deferred, + resource, request, position) < 0) + { + return -1; + } + + // + // Don't send the notification again. + // + + split -> setState(split_notified); + } + #if defined(TEST) || defined(SPLIT) + else + { + *logofs << "handleRestart: SPLIT! Split for request " + << split -> getRequest() << " and position " + << split -> getPosition() << " was already " + << "notified.\n" << logofs_flush; + } + #endif + } + + // + // Don't send the end split if we are still + // in the middle of a start-split/end-split + // sequence. We'll send a no-split at the + // time the end-split is received. + // + + if (splitStore -> getSize() == 0 && + splitStore -> getResource() != splitState_.resource) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleRestart: SPLIT! Deferred agent split event " + << "TYPE#" << (unsigned) opcodeStore_ -> endSplitNotify + << " [end split] with resource " << resource << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + if (handleNotify(notify_end_split, sequence_deferred, + resource, nothing, nothing) < 0) + { + return -1; + } + } + #if defined(TEST) || defined(SPLIT) + else if (splitStore -> getSize() == 0 && + splitStore -> getResource() == splitState_.resource) + { + *logofs << "handleRestart: SPLIT! WARNING! The split store " + << "for resource " << resource << " was emptied in the " + << "split sequence at " << strMsTimestamp() << ".\n" + << logofs_flush; + } + #endif + } + + // + // Remove the split store if it's empty. + // + + if (splitStore != NULL && splitStore -> getSize() == 0 && + splitStore -> getResource() != splitState_.resource) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleRestart: SPLIT! Removing the split store [" + << resource << "] at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + handleSplitStoreRemove(&splitResources_, resource); + + if (clientStore_ -> getSplitTotalSize() == 0) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleRestart: SPLIT! Deferred agent split event " + << "TYPE#" << (unsigned) opcodeStore_ -> emptySplitNotify + << " [empty split] for FD#" << fd_ << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + if (handleNotify(notify_empty_split, sequence_deferred, + nothing, nothing, nothing) < 0) + { + return -1; + } + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleRestart: SPLIT! There are " << clientStore_ -> + getSplitTotalSize() << " messages and " << clientStore_ -> + getSplitTotalStorageSize() << " bytes to send in " + << "the split stores.\n" << logofs_flush; + + if ((clientStore_ -> getSplitTotalSize() != 0 && + clientStore_ -> getSplitTotalStorageSize() == 0) || + (clientStore_ -> getSplitTotalSize() == 0 && + clientStore_ -> getSplitTotalStorageSize() != 0)) + { + #ifdef PANIC + *logofs << "handleRestart: PANIC! Inconsistency detected " + << "while handling the split stores.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } + + #endif + } + + return 1; +} + +int ClientChannel::handleTaintLameRequest(unsigned char &opcode, const unsigned char *&buffer, + unsigned int &size) +{ + // + // Test the efficiency of the encoding + // without these RENDER requests. + // + + if (opcode == opcodeStore_ -> renderExtension && + (*(buffer + 1) == X_RenderCompositeGlyphs8 || + *(buffer + 1) == X_RenderCompositeGlyphs16 || + *(buffer + 1) == X_RenderCompositeGlyphs32 || + *(buffer + 1) == X_RenderAddGlyphs || + *(buffer + 1) == X_RenderTrapezoids)) + { + #ifdef TEST + *logofs << "handleTaintLameRequest: Tainting request " + << "OPCODE#" << (unsigned int) opcode << " MINOR#" + << (unsigned int) *(buffer + 1) << " for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + opcode = X_NoOperation; + + return 1; + } + + return 0; +} + +int ClientChannel::handleTaintSyncRequest(unsigned char &opcode, const unsigned char *&buffer, + unsigned int &size) +{ + // + // Should short-circuit other common replies + // whose values could be queried only once. + // Examples are X_InterAtom, X_ListExtension + // and X_QueryExtension. + // + + if (taintCounter_ >= control -> TaintThreshold) + { + #ifdef DEBUG + *logofs << "handleTaintSyncRequest: Reset taint counter after " + << taintCounter_ << " replies managed.\n" + << logofs_flush; + #endif + + taintCounter_ = 0; + + return 0; + } + + // + // Check if we are rolling the counter. + // The client sequence number has not + // been incremented yet in the loop. + // + + unsigned int sequence = (clientSequence_ + 1) & 0xffff; + + #ifdef DEBUG + *logofs << "handleTaintSyncRequest: Opcode is " << (unsigned) opcode + << " expected client sequence is " << sequence + << ".\n" << logofs_flush; + #endif + + if (sequence == 0xffff) + { + return 0; + } + + unsigned short t1; + unsigned char t2; + + // + // Check if there is a previous reply + // pending. + // + + if (sequenceQueue_.peek(t1, t2) != 0) + { + #ifdef DEBUG + *logofs << "handleTaintSyncRequest: Skipping taint of reply due to " + << "pending request OPCODE#" << t1 << " with sequence " + << (unsigned int) t2 << ".\n" << logofs_flush; + #endif + + return 0; + } + + #ifdef DEBUG + *logofs << "handleTaintSyncRequest: Suppressing get input focus " + << "request for FD#" << fd_ << " with sequence " + << sequence << ".\n" << logofs_flush; + #endif + + unsigned char *reply = writeBuffer_.addMessage(32); + + *(reply + 0) = X_Reply; + + PutUINT(sequence, reply + 2, bigEndian_); + + PutULONG(0, reply + 4, bigEndian_); + + // + // Set revert-to to none. + // + + *(reply + 1) = 0; + + // + // Set focus to none. + // + + PutULONG(0, reply + 8, bigEndian_); + + // + // Save the sequence number, not incremented + // yet, we used to auto-generate this reply. + // + + lastSequence_ = clientSequence_ + 1; + + #ifdef TEST + *logofs << "handleTaintSyncRequest: Registered " << lastSequence_ + << " as last auto-generated sequence number.\n" + << logofs_flush; + #endif + + // + // Taint the request to a X_NoOperation. + // + + opcode = X_NoOperation; + + // + // We may assume that the client has finished + // drawing and flush immediately, even if this + // seems to perceively affect the performance. + // + // priority_++; + // + + if (handleFlush(flush_if_any) < 0) + { + return -1; + } + + taintCounter_++; + + return 1; +} + +int ClientChannel::handleTaintSyncError(unsigned char opcode) +{ + if (control -> TaintReplies > 0) + { + // + // By enabling short-circuiting of replies + // some window managers can get confused + // by some otherwise innocuous X errors. + // + + if (opcode == X_GrabKey || opcode == X_ReparentWindow || + opcode == X_ConfigureWindow) + { + #if defined(TEST) || defined(OPCODES) + *logofs << "handleTaintSyncError: WARNING! Suppressed error " + << "on OPCODE#" << (unsigned int) opcode << " for FD#" + << fd_ << " sequence " << lastSequence_ << " (real was " + << serverSequence_ << ").\n" << logofs_flush; + #endif + + return 1; + } + } + + return 0; +} + +int ClientChannel::handleNotify(T_notification_type type, T_sequence_mode mode, + int resource, int request, int position) +{ + if (finish_ == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleNotify: Discarding notification on " + << "channel for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + + // + // Add a new message to the write buffer. + // + + unsigned char *event = writeBuffer_.addMessage(32); + + // + // Event is ClientMessage, atom and + // window are 0, format is 32. + // + + *(event + 0) = ClientMessage; + + PutULONG(0, event + 4, bigEndian_); + PutULONG(0, event + 8, bigEndian_); + + *(event + 1) = 32; + + // + // If the event follows immediately the request (that is the + // sequence mode is 'immediate') then the sequence number is + // the one of the last request, else it should be the last + // sequence number encoded by peer proxy but, as we are ins- + // erting events in the stream, we must ensure that the se- + // quence we send is not less than the last sequence we have + // auto-generated. + // + + if (mode == sequence_immediate) + { + // + // Save the sequence number we used + // to auto-generate this event. + // + + lastSequence_ = clientSequence_; + + #if defined(TEST) || defined(INFO) + *logofs << "handleNotify: Registered " << lastSequence_ + << " as last auto-generated sequence number.\n" + << logofs_flush; + #endif + } + else + { + if (serverSequence_ > lastSequence_) + { + #ifdef DEBUG + *logofs << "handleNotify: Updating last event's sequence " + << lastSequence_ << " to X server's sequence number " + << serverSequence_ << " for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + lastSequence_ = serverSequence_; + } + #ifdef DEBUG + else if (serverSequence_ < lastSequence_) + { + // + // Use our last auto-generated sequence. + // + + *logofs << "handleNotify: Tainting sequence number " + << serverSequence_ << " to last event's sequence " + << lastSequence_ << " for FD#" << fd_ << ".\n" + << logofs_flush; + } + #endif + } + + PutUINT(lastSequence_, event + 2, bigEndian_); + + // + // Be sure we set to void the fields that + // are not significant for the specific + // notification message. + // + + PutULONG(nothing, event + 16, bigEndian_); + PutULONG(nothing, event + 20, bigEndian_); + PutULONG(nothing, event + 24, bigEndian_); + + switch (type) + { + case notify_no_split: + { + PutULONG(opcodeStore_ -> noSplitNotify, + event + 12, bigEndian_); + + PutULONG(resource, event + 16, bigEndian_); + + break; + } + case notify_start_split: + { + PutULONG(opcodeStore_ -> startSplitNotify, + event + 12, bigEndian_); + + PutULONG(resource, event + 16, bigEndian_); + + break; + } + case notify_commit_split: + { + PutULONG(opcodeStore_ -> commitSplitNotify, + event + 12, bigEndian_); + + PutULONG(resource, event + 16, bigEndian_); + + PutULONG(request, event + 20, bigEndian_); + + PutULONG(position, event + 24, bigEndian_); + + break; + } + case notify_end_split: + { + PutULONG(opcodeStore_ -> endSplitNotify, + event + 12, bigEndian_); + + PutULONG(resource, event + 16, bigEndian_); + + break; + } + case notify_empty_split: + { + PutULONG(opcodeStore_ -> emptySplitNotify, + event + 12, bigEndian_); + break; + } + default: + { + #ifdef PANIC + *logofs << "handleNotify: PANIC! Unrecognized notify " + << "TYPE#" << type << ".\n" + << logofs_flush; + #endif + + return -1; + } + } + + #if defined(TEST) || defined(INFO) || defined (SPLIT) + + *logofs << "handleNotify: Sending " + << (mode == sequence_immediate ? "immediate " : "deferred ") + << "agent notify event TYPE#" << GetULONG(event + 12, bigEndian_) + << logofs_flush; + + if (resource != nothing) + { + *logofs << " with resource " << GetULONG(event + 16, bigEndian_) + << logofs_flush; + + if (request != nothing && position != nothing) + { + *logofs << " request " << GetULONG(event + 20, bigEndian_) + << " position " << GetULONG(event + 24, bigEndian_) + << logofs_flush; + } + } + + *logofs << ".\n" << logofs_flush; + + #endif + + // + // Send the notification now. + // + + if (handleFlush(flush_if_any) < 0) + { + return -1; + } + + return 1; +} + +int ClientChannel::handleCommitSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + // + // Get the data of the request to be + // committed. + // + + unsigned char request = *(buffer + 5); + + MessageStore *store = clientStore_ -> getRequestStore(request); + + if (store == NULL) + { + #ifdef PANIC + *logofs << "handleCommitSplitRequest: PANIC! Can't commit split for " + << "request OPCODE#" << (unsigned int) request + << ". No message store found.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't commit split for request " + << "OPCODE#" << (unsigned int) request + << ". No message store found.\n"; + + return -1; + } + + // + // The position in cache of the message + // to commit. Encode it as difference in + // respect to the last encoded value. + // + + unsigned int position = GetULONG(buffer + 8, bigEndian_); + + unsigned char resource = *(buffer + 1); + unsigned int commit = *(buffer + 4); + + #if defined(TEST) || defined(SPLIT) + + if (commit == 1) + { + *logofs << "handleCommitSplitRequest: SPLIT! Committing request " + << "OPCODE#" << (unsigned) request << " at position " + << position << " for FD#" << fd_ << " with resource " + << (unsigned) resource << ".\n" << logofs_flush; + } + else + { + *logofs << "handleCommitSplitRequest: SPLIT! Discarding request " + << "OPCODE#" << (unsigned) request << " at position " + << position << " for FD#" << fd_ << " with resource " + << (unsigned) resource << ".\n" << logofs_flush; + } + + #endif + + encodeBuffer.encodeOpcodeValue(request, clientCache_ -> opcodeCache); + + int diffCommit = position - splitState_.commit; + + splitState_.commit = position; + + encodeBuffer.encodeValue(diffCommit, 32, 5); + + // + // Send the resource id and the commit + // flag. + // + + encodeBuffer.encodeCachedValue(resource, 8, + clientCache_ -> resourceCache); + + encodeBuffer.encodeBoolValue(commit); + + // + // Remove the split from the split queue. + // + + Split *split = handleSplitCommitRemove(request, resource, splitState_.commit); + + if (split == NULL) + { + return -1; + } + + clientStore_ -> getCommitStore() -> update(split); + + // + // Free the split. + // + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleCommitSplitRequest: SPLIT! Freeing up the " + << "committed split.\n" << logofs_flush; + #endif + + delete split; + + return 1; +} + +int ClientChannel::handleAbortSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + unsigned char resource = *(buffer + 1); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleAbortSplitRequest: SPLIT! Handling abort split " + << "request for FD#"<< fd_ << " and resource " + << (unsigned int) resource << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(resource, 8, + clientCache_ -> resourceCache); + + SplitStore *splitStore = clientStore_ -> getSplitStore(resource); + + if (splitStore == NULL) + { + #ifdef WARNING + *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The split " + << "store [" << (unsigned int) resource << "] " + << "is already empty.\n" << logofs_flush; + #endif + + return 0; + } + + // + // Loop through the messages in the split + // store and discard from the memory cache + // the messages that are still incomplete. + // Then remove the message from the split + // store. + // + + #if defined(TEST) || defined(SPLIT) + + clientStore_ -> dumpSplitStore(resource); + + #endif + + int splits = 0; + + Split *splitMessage; + + for (;;) + { + splitMessage = splitStore -> getFirstSplit(); + + if (splitMessage == NULL) + { + // + // Check if we had created the store + // but no message was added yet. + // + + #ifdef WARNING + + if (splits == 0) + { + *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The " + << "split store [" << (unsigned int) resource + << "] is unexpectedly empty.\n" + << logofs_flush; + } + + #endif + + break; + } + + // + // Splits already aborted can't be in the + // split store. + // + + #if defined(TEST) || defined(SPLIT) + + if (splitMessage -> getState() == split_aborted) + { + *logofs << "handleAbortSplitRequest: PANIC! SPLIT! Found an " + << "aborted split in store [" << (unsigned int) resource + << "].\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + if (splitMessage -> getAction() == IS_HIT) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleAbortSplitRequest: SPLIT! Removing the " + << "split from the memory cache.\n" + << logofs_flush; + #endif + + splitMessage -> getStore() -> remove(splitMessage -> getPosition(), + use_checksum, discard_data); + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleAbortSplitRequest: SPLIT! Removing the " + << "split from the split store.\n" + << logofs_flush; + #endif + + splitMessage = splitStore -> pop(); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleAbortSplitRequest: SPLIT! Freeing up the " + << "aborted split.\n" << logofs_flush; + #endif + + delete splitMessage; + + splits++; + } + + // + // If the start-split/end-split sequence + // was closed, send the notification now, + // else wait for the end-split. + // + + if (resource != splitState_.resource) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleAbortSplitRequest: SPLIT! Sending the " + << "deferred [end split] event.\n" + << logofs_flush; + #endif + + handleRestart(sequence_deferred, resource); + } + #if defined(TEST) || defined(SPLIT) + else + { + *logofs << "handleAbortSplitRequest: WARNING! SPLIT! Still " + << "waiting for the closure of the split " + << "sequence.\n" << logofs_flush; + } + #endif + + // + // Check if there is any other store + // having splits to send. + // + + handleSplitPending(); + + return (splits > 0); +} + +int ClientChannel::handleFinishSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + unsigned char resource = *(buffer + 1); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleFinishSplitRequest: SPLIT! Handling finish split " + << "request for FD#"<< fd_ << " and resource " + << (unsigned int) resource << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(resource, 8, + clientCache_ -> resourceCache); + + // + // We need to get the protocol statistics + // for the finish message we are handling + // here because sending a new split will + // reset the bits counter. + // + + int bits = encodeBuffer.diffBits(); + + statistics -> addRequestBits(opcode, size << 3, bits); + + SplitStore *splitStore = clientStore_ -> getSplitStore(resource); + + if (splitStore == NULL) + { + #ifdef WARNING + *logofs << "handleFinishSplitRequest: WARNING! SPLIT! The split " + << "store [" << (unsigned int) resource << "] " + << "is already empty.\n" << logofs_flush; + #endif + + return 0; + } + + // + // Send all the split queued for the given + // resource until the split store becomes + // empty. + // + + #if defined(TEST) || defined(SPLIT) + + clientStore_ -> dumpSplitStore(resource); + + #endif + + Split *splitMessage; + + int total = MESSAGE_DATA_LIMIT; + + int bytes = total; + int splits = 0; + + for (;;) + { + splitMessage = splitStore -> getFirstSplit(); + + if (splitMessage == NULL) + { + // + // We have presumably created the store + // after a start split but no message + // was added yet. + // + + #ifdef WARNING + *logofs << "handleFinishSplitRequest: WARNING! SPLIT! The " + << "split store [" << (unsigned int) resource + << "] is unexpectedly empty.\n" + << logofs_flush; + #endif + + break; + } + + // + // Splits already aborted can't be in the + // split store. + // + + #if defined(TEST) || defined(SPLIT) + + if (splitMessage -> getState() == split_aborted) + { + *logofs << "handleFinishSplitRequest: PANIC! SPLIT! Found an " + << "aborted split in store [" << (unsigned int) resource + << "].\n" << logofs_flush; + + HandleCleanup(); + } + + *logofs << "handleFinishSplitRequest: SPLIT! Sending more " + << "data for store [" << (unsigned int) resource + << "].\n" << logofs_flush; + #endif + + if (handleSplitSend(encodeBuffer, resource, splits, bytes) < 0) + { + return -1; + } + + // + // Check if the split store was deleted. + // + + if (clientStore_ -> getSplitStore(resource) == NULL) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleFinishSplitRequest: SPLIT! Exiting " + << "from the finish loop with split store [" + << (unsigned int) resource << "] destroyed.\n" + << logofs_flush; + #endif + + break; + } + } + + // + // Check if there is any other store + // having splits to send. + // + + handleSplitPending(); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleFinishSplitRequest: SPLIT! Sent " << splits + << " splits and " << total - bytes << " bytes for FD#" << fd_ + << " with " << clientStore_ -> getSplitTotalStorageSize() + << " bytes and [" << clientStore_ -> getSplitTotalSize() + << "] splits remaining.\n" << logofs_flush; + #endif + + return (splits > 0); +} + +int ClientChannel::handleConfiguration() +{ + #ifdef TEST + *logofs << "ClientChannel: Setting new buffer parameters.\n" + << logofs_flush; + #endif + + readBuffer_.setSize(control -> ClientInitialReadSize, + control -> ClientMaximumBufferSize); + + writeBuffer_.setSize(control -> TransportXBufferSize, + control -> TransportXBufferThreshold, + control -> TransportMaximumBufferSize); + + transport_ -> setSize(control -> TransportXBufferSize, + control -> TransportXBufferThreshold, + control -> TransportMaximumBufferSize); + + return 1; +} + +int ClientChannel::handleFinish() +{ + #ifdef TEST + *logofs << "ClientChannel: Finishing channel for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + congestion_ = 0; + priority_ = 0; + + finish_ = 1; + + taintCounter_ = 0; + + splitState_.resource = nothing; + splitState_.pending = 0; + splitState_.commit = 0; + splitState_.mode = split_none; + + transport_ -> finish(); + + return 1; +} + +// +// If differential compression is disabled then use the +// most simple encoding but handle the image requests +// and the X_ListExtensions and X_QueryExtension messa- +// ges (needed to detect the opcode of the shape or the +// other extensions) in the usual way. +// + +int ClientChannel::handleFastReadRequest(EncodeBuffer &encodeBuffer, const unsigned char &opcode, + const unsigned char *&buffer, const unsigned int &size) +{ + // + // All the NX requests are handled in the + // main message loop. The X_PutImage can + // be handled here only if the split was + // not requested (since ProtoStep7 #issue 108). + // + + if ((opcode >= X_NXFirstOpcode && opcode <= X_NXLastOpcode) || + (opcode == X_PutImage && splitState_.resource != nothing) || + opcode == X_ListExtensions || + opcode == X_QueryExtension) + { + return 0; + } + + #ifdef DEBUG + *logofs << "handleFastReadRequest: Encoding raw request OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ + << " with size " << size << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeMemory(buffer, size); + + // + // Put request on the fast track + // if it needs a reply. + // + + switch (opcode) + { + case X_GetAtomName: + case X_GetGeometry: + case X_GetInputFocus: + case X_GetModifierMapping: + case X_GetKeyboardMapping: + case X_GetProperty: + case X_GetSelectionOwner: + case X_GrabPointer: + case X_GrabKeyboard: + case X_ListExtensions: + case X_ListFonts: + case X_LookupColor: + case X_AllocNamedColor: + case X_QueryPointer: + case X_GetWindowAttributes: + case X_QueryTree: + case X_QueryBestSize: + case X_QueryColors: + case X_QueryFont: + case X_TranslateCoords: + case X_GetImage: + case X_GetPointerMapping: + case X_GetKeyboardControl: + case X_InternAtom: + case X_AllocColor: + { + sequenceQueue_.push(clientSequence_, opcode); + + priority_++; + + break; + } + default: + { + break; + } + } + + int bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) + + *logofs << "handleFastReadRequest: Handled raw request OPCODE#" + << (unsigned int) opcode << " (" << DumpOpcode(opcode) << ")" + << " for FD#" << fd_ << " sequence " << clientSequence_ + << ". " << size << " bytes in, " << bits << " bits (" + << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; + + #endif + + statistics -> addRequestBits(opcode, size << 3, bits); + + if (opcode == opcodeStore_ -> renderExtension) + { + statistics -> addRenderRequestBits(*(buffer + 1), size << 3, bits); + } + + return 1; +} + +int ClientChannel::handleFastWriteReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + if ((opcode >= X_NXFirstOpcode && + opcode <= X_NXLastOpcode) || + opcode == X_ListExtensions || + opcode == X_QueryExtension) + { + return 0; + } + + #ifdef DEBUG + *logofs << "handleFastWriteReply: Decoding raw reply OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + buffer = writeBuffer_.addMessage(8); + + #ifndef __sun + + unsigned int *next = (unsigned int *) decodeBuffer.decodeMemory(8); + + *((unsigned int *) buffer) = *next++; + *((unsigned int *) (buffer + 4)) = *next; + + #else /* #ifndef __sun */ + + memcpy(buffer, decodeBuffer.decodeMemory(8), 8); + + #endif /* #ifndef __sun */ + + size = 32 + (GetULONG(buffer + 4, bigEndian_) << 2); + + writeBuffer_.registerPointer(&buffer); + + if (writeBuffer_.getAvailable() < size - 8 || + (int) size >= control -> TransportFlushBufferSize) + { + #ifdef DEBUG + *logofs << "handleFastWriteReply: Using scratch buffer for OPCODE#" + << (unsigned int) opcode << " with size " << size << " and " + << writeBuffer_.getLength() << " bytes in buffer.\n" + << logofs_flush; + #endif + + writeBuffer_.removeMessage(8); + + buffer = writeBuffer_.addScratchMessage(((unsigned char *) + decodeBuffer.decodeMemory(size - 8)) - 8, size); + } + else + { + writeBuffer_.addMessage(size - 8); + + #ifndef __sun + + if (size == 32) + { + next = (unsigned int *) decodeBuffer.decodeMemory(size - 8); + + for (int i = 8; i < 32; i += sizeof(unsigned int)) + { + *((unsigned int *) (buffer + i)) = *next++; + } + } + else + { + memcpy(buffer + 8, decodeBuffer.decodeMemory(size - 8), size - 8); + } + + #else /* #ifndef __sun */ + + memcpy(buffer + 8, decodeBuffer.decodeMemory(size - 8), size - 8); + + #endif /* #ifndef __sun */ + } + + writeBuffer_.unregisterPointer(); + + // + // We don't need to write our local sequence + // number. Replies are always sent with the + // original X server's sequence number. + // + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleFastWriteReply: Handled raw reply OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ << " with sequence " + << serverSequence_ << ". Output size is " << size << ".\n" + << logofs_flush; + #endif + + #ifdef DEBUG + *logofs << "handleFastWriteReply: Length of sequence queue is " + << sequenceQueue_.length() << ".\n" << logofs_flush; + #endif + + statistics -> addRepliedRequest(opcode); + + handleFlush(flush_if_needed); + + return 1; +} + +int ClientChannel::handleFastWriteEvent(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + #ifdef DEBUG + *logofs << "handleFastWriteEvent: Decoding raw " + << (opcode == X_Error ? "error" : "event") << " OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + size = 32; + + buffer = writeBuffer_.addMessage(size); + + #ifndef __sun + + unsigned int *next = (unsigned int *) decodeBuffer.decodeMemory(size); + + for (int i = 0; i < 32; i += sizeof(unsigned int)) + { + *((unsigned int *) (buffer + i)) = *next++; + } + + #else /* #ifndef __sun */ + + memcpy(buffer, decodeBuffer.decodeMemory(size), size); + + #endif /* #ifndef __sun */ + + // + // Use our local sequence number. + // + + PutUINT(lastSequence_, buffer + 2, bigEndian_); + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleFastWriteEvent: Handled raw " + << (opcode == X_Error ? "error" : "event") << " OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ << " with sequence " + << lastSequence_ << ". Output size is " << size << ".\n" + << logofs_flush; + #endif + + // + // Check if we need to suppress the error. + // + + if (opcode == X_Error && handleTaintSyncError(*(buffer + 10)) > 0) + { + #if defined(TEST) || defined(OPCODES) + *logofs << "handleFastWriteEvent: WARNING! Suppressed error OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ + << " with sequence " << lastSequence_ << ".\n" + << logofs_flush; + #endif + + writeBuffer_.removeMessage(32); + } + + handleFlush(flush_if_needed); + + return 1; +} + +int ClientChannel::handleShmemRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + // + // Will push sequence and set + // priority according to stage. + // + + unsigned int stage = *(buffer + 1); + + #ifdef TEST + *logofs << "handleShmemRequest: Encoding shmem request " + << "OPCODE#" << (unsigned int) opcode << " for FD#" + << fd_ << " with size " << size << " at stage " + << stage << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeValue(stage, 2); + + if (stage == 0) + { + unsigned int enableClient = 0; + unsigned int enableServer = 0; + + if (control -> ShmemClient == 1) + { + enableClient = *(buffer + 4); + } + + if (control -> ShmemServer == 1) + { + enableServer = *(buffer + 5); + } + + encodeBuffer.encodeBoolValue(enableClient); + encodeBuffer.encodeBoolValue(enableServer); + + unsigned int clientSegment = GetULONG(buffer + 8, bigEndian_); + unsigned int serverSegment = GetULONG(buffer + 12, bigEndian_); + + encodeBuffer.encodeValue(clientSegment, 29, 9); + encodeBuffer.encodeValue(serverSegment, 29, 9); + + #ifdef TEST + *logofs << "handleShmemRequest: Enable client is " + << enableClient << " enable server is " << enableServer + << " client segment is " << (void *) clientSegment + << " server segment is " << (void *) serverSegment + << ".\n" << logofs_flush; + #endif + + #ifdef TEST + *logofs << "handleShmemRequest: Size of the shared memory " + << "segment will be " << control -> ShmemServerSize + << ".\n" << logofs_flush; + #endif + } + + if (stage != 1) + { + sequenceQueue_.push(clientSequence_, opcodeStore_ -> + getShmemParameters); + + priority_++; + } + + return 1; +} + +int ClientChannel::handleShmemReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + #ifdef TEST + *logofs << "handleShmemReply: Received shmem parameters " + << "reply OPCODE#" << (unsigned int) opcode + << ".\n" << logofs_flush; + #endif + + size = 32; + buffer = writeBuffer_.addMessage(size); + + unsigned int stage; + + decodeBuffer.decodeValue(stage, 2); + + *(buffer + 1) = stage; + + if (stage == 2) + { + unsigned int clientEnabled; + unsigned int serverEnabled; + + decodeBuffer.decodeBoolValue(clientEnabled); + decodeBuffer.decodeBoolValue(serverEnabled); + + // + // Client support is not implemented + // and not useful. It is here only + // for compatibility. + // + + clientEnabled = 0; + + *(buffer + 8) = clientEnabled; + *(buffer + 9) = serverEnabled; + + PutULONG(0, buffer + 12, bigEndian_); + + if (serverEnabled == 1) + { + #ifdef TEST + *logofs << "handleShmemReply: Enabled shared memory " + << "support in X server with segment size " + << control -> ShmemServerSize << ".\n" + << logofs_flush; + #endif + + PutULONG(control -> ShmemServerSize, buffer + 16, bigEndian_); + } + else + { + PutULONG(0, buffer + 16, bigEndian_); + } + } + else + { + *(buffer + 8) = 0; + *(buffer + 9) = 0; + + PutULONG(0, buffer + 12, bigEndian_); + PutULONG(0, buffer + 16, bigEndian_); + } + + return 1; +} + +int ClientChannel::handleFontRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + #ifdef TEST + *logofs << "handleFontRequest: Encoding font request " + << "OPCODE#" << (unsigned int) opcode << " for FD#" + << fd_ << " with size " << size << ".\n" + << logofs_flush; + #endif + + sequenceQueue_.push(clientSequence_, opcodeStore_ -> + getFontParameters); + + return 1; +} + +int ClientChannel::handleFontReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + #ifdef TEST + *logofs << "handleFontReply: Received font operation " + << "reply OPCODE#" << (unsigned int) opcode + << ".\n" << logofs_flush; + #endif + + unsigned int length; + + decodeBuffer.decodeValue(length, 8); + + size = 32 + RoundUp4(length + 1); + buffer = writeBuffer_.addMessage(size); + + unsigned char *next = buffer + 32; + + *next++ = length; + + decodeBuffer.decodeTextData(next, length); + + #ifdef TEST + + *logofs << "handleFontReply: Received tunneled font server " + << "path '"; + + for (unsigned int i = 0; i < length; i++) + { + *logofs << *(buffer + 32 + 1 + i); + } + + *logofs << "' for FD#" << fd_ << ".\n" << logofs_flush; + + #endif + + if (fontPort_ == -1) + { + // + // The local side is not going to forward + // the font server connections. + // + + #ifdef TEST + *logofs << "handleFontReply: WARNING! Returning an empty " + << "font server path.\n" << logofs_flush; + #endif + + writeBuffer_.removeMessage(size); + + size = 36; + buffer = writeBuffer_.addMessage(size); + + // + // Set the length of the returned + // path to 0. + // + + *(buffer + 32) = 0; + } + #ifdef TEST + else + { + *logofs << "handleFontReply: Returning the received " + << "font server path.\n" << logofs_flush; + } + #endif + + return 1; +} + +int ClientChannel::handleCacheRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + #ifdef TEST + *logofs << "handleCacheRequest: Handling cache request " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + enableCache_ = *(buffer + 4); + enableSplit_ = *(buffer + 5); + enableSave_ = *(buffer + 6); + enableLoad_ = *(buffer + 7); + + #ifdef TEST + *logofs << "handleCacheRequest: Set cache parameters to " + << " cache " << enableCache_ << " split " << enableSplit_ + << " save " << enableSave_ << " load " << enableLoad_ + << ".\n" << logofs_flush; + #endif + + // + // Encode all the parameters as a + // single unsigned int so we can + // use an int cache. + // + + unsigned int mask = enableSave_ << 8 | enableLoad_; + + encodeBuffer.encodeCachedValue(mask, 32, clientCache_ -> + setCacheParametersCache); + return 0; +} + +int ClientChannel::handleStartSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + #if defined(TEST) || defined(SPLIT) + *logofs << "handleStartSplitRequest: SPLIT! Handling start split " + << "request for FD#"<< fd_ << ".\n" << logofs_flush; + #endif + + if (splitState_.resource != nothing) + { + #ifdef PANIC + *logofs << "handleStartSplitRequest: PANIC! SPLIT! Split requested " + << "for resource id " << (unsigned int) *(buffer + 1) + << " while handling resource " << splitState_.resource + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Split requested for " + << "resource id " << (unsigned int) *(buffer + 1) + << " while handling resource " << splitState_.resource + << ".\n"; + + return -1; + } + else if (fd_ != firstClient_) + { + // + // It can be that an auxiliary channel is the + // first to connect, then comes the agent that + // is actually using the NX opcodes. + // + + #ifdef WARNING + *logofs << "handleStartSplitRequest: WARNING SPLIT! Split requested " + << "on FD#" << fd_ << " while expecting FD#" << firstClient_ + << ".\n" << logofs_flush; + #endif + + firstClient_ = fd_; + } + + // + // Set the agent's resource for which we are + // going to split the request. + // + + splitState_.resource = *(buffer + 1); + + #if defined(TEST) || defined(SPLIT) + + *logofs << "handleStartSplitRequest: SPLIT! Registered id " + << splitState_.resource << " as resource " + << "waiting for a split.\n" << logofs_flush; + + if (clientStore_ -> getSplitStore(splitState_.resource) != NULL) + { + *logofs << "handleStartSplitRequest: WARNING! SPLIT! A split " + << "store for resource id " << splitState_.resource + << " already exists.\n" << logofs_flush; + + clientStore_ -> dumpSplitStore(splitState_.resource); + } + + #endif + + // + // Send the selected resource to the remote. + // + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeCachedValue(splitState_.resource, 8, + clientCache_ -> resourceCache); + + splitState_.mode = (T_split_mode) *(buffer + 4); + + if (splitState_.mode != NXSplitModeAsync && + splitState_.mode != NXSplitModeSync) + { + splitState_.mode = (T_split_mode) control -> SplitMode; + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleStartSplitRequest: SPLIT! Set split " + << "mode to '" << splitState_.mode << "' with " + << "provided value '" << (unsigned) *(buffer + 4) + << "'.\n" << logofs_flush; + #endif + } + + #if defined(TEST) || defined(SPLIT) + + if (splitState_.mode == NXSplitModeAsync) + { + *logofs << "handleStartSplitRequest: SPLIT! Selected split " + << "mode is [split_async].\n" << logofs_flush; + } + else if (splitState_.mode == NXSplitModeSync) + { + *logofs << "handleStartSplitRequest: SPLIT! Selected split " + << "mode is [split_sync].\n" << logofs_flush; + } + + clientStore_ -> dumpSplitStores(); + + #endif + + return 1; +} + +int ClientChannel::handleEndSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + #if defined(TEST) || defined(SPLIT) + *logofs << "handleEndSplitRequest: SPLIT! Handling end split " + << "request for FD#"<< fd_ << ".\n" << logofs_flush; + #endif + + // + // Verify that the agent resource matches. + // + + if (splitState_.resource == nothing) + { + #ifdef PANIC + *logofs << "handleEndSplitRequest: PANIC! SPLIT! Received an end of " + << "split for resource id " << (unsigned int) *(buffer + 1) + << " without a previous start.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Received an end of split " + << "for resource id " << (unsigned int) *(buffer + 1) + << " without a previous start.\n"; + + return -1; + } + else if (splitState_.resource != *(buffer + 1)) + { + #ifdef PANIC + *logofs << "handleEndSplitRequest: PANIC! SPLIT! Invalid resource id " + << (unsigned int) *(buffer + 1) << " received while " + << "waiting for resource id " << splitState_.resource + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid resource id " + << (unsigned int) *(buffer + 1) << " received while " + << "waiting for resource id " << splitState_.resource + << ".\n"; + + return -1; + } + + // + // Send the selected resource to the remote. + // + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeCachedValue(splitState_.resource, 8, + clientCache_ -> resourceCache); + + // + // Send the split notification events + // to the agent. + // + + handleRestart(sequence_immediate, splitState_.resource); + + // + // Check if we still have splits to send. + // + + handleSplitPending(); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleEndSplitRequest: SPLIT! Reset id " + << splitState_.resource << " as resource " + << "selected for splits.\n" << logofs_flush; + #endif + + splitState_.resource = nothing; + splitState_.mode = split_none; + + #if defined(TEST) || defined(SPLIT) + + clientStore_ -> dumpSplitStores(); + + #endif + + return 1; +} + +void ClientChannel::handleDecodeCharInfo(DecodeBuffer &decodeBuffer, unsigned char *nextDest) +{ + unsigned int value; + + decodeBuffer.decodeCachedValue(value, 32, + *serverCache_ -> queryFontCharInfoCache[0], 6); + + PutUINT(value & 0xffff, nextDest, bigEndian_); + PutUINT(value >> 16, nextDest + 10, bigEndian_); + + nextDest += 2; + + for (unsigned int i = 1; i < 5; i++) + { + unsigned int value; + + decodeBuffer.decodeCachedValue(value, 16, + *serverCache_ -> queryFontCharInfoCache[i], 6); + + PutUINT(value, nextDest, bigEndian_); + + nextDest += 2; + } +} + +int ClientChannel::setBigEndian(int flag) +{ + bigEndian_ = flag; + + return 1; +} + +int ClientChannel::setReferences() +{ + #ifdef TEST + *logofs << "ClientChannel: Initializing the static " + << "members for the client channels.\n" + << logofs_flush; + #endif + + #ifdef REFERENCES + + references_ = 0; + + #endif + + return 1; +} diff --git a/nxcomp/src/ClientChannel.h b/nxcomp/src/ClientChannel.h new file mode 100644 index 000000000..ae92648d5 --- /dev/null +++ b/nxcomp/src/ClientChannel.h @@ -0,0 +1,434 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ClientChannel_H +#define ClientChannel_H + +#include "List.h" +#include "Channel.h" + +#include "SequenceQueue.h" + +#include "ClientReadBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// If defined, the client channel will +// have the chance of suppressing more +// opcodes for test purposes. +// + +#undef LAME + +// +// Define this to log a line when a +// channel is created or destroyed. +// + +#undef REFERENCES + +// +// This class implements the X client +// side compression of the protocol. +// + +class ClientChannel : public Channel +{ + public: + + ClientChannel(Transport *transport, StaticCompressor *compressor); + + virtual ~ClientChannel(); + + virtual int handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, + unsigned int length); + + virtual int handleWrite(const unsigned char *message, unsigned int length); + + virtual int handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, + T_store_action action, int position, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + virtual int handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, + T_store_action action, int position, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) + { + return 0; + } + + virtual int handleSplit(EncodeBuffer &encodeBuffer); + + virtual int handleSplit(DecodeBuffer &decodeBuffer) + { + return 0; + } + + virtual int handleSplitEvent(EncodeBuffer &encodeBuffer, Split *split); + + virtual int handleSplitEvent(DecodeBuffer &decodeBuffer); + + virtual int handleMotion(EncodeBuffer &encodeBuffer) + { + return 0; + } + + virtual int handleCompletion(EncodeBuffer &encodeBuffer) + { + return 0; + } + + virtual int handleConfiguration(); + + virtual int handleFinish(); + + virtual int handleAsyncEvents() + { + return 0; + } + + virtual int needSplit() const + { + #if defined(TEST) || defined(SPLIT) + *logofs << "needSplit: SPLIT! Returning pending split " + << "flag " << splitState_.pending << " with " + << clientStore_ -> getSplitTotalSize() + << " splits in the split stores.\n" + << logofs_flush; + #endif + + return splitState_.pending; + } + + virtual int needMotion() const + { + return 0; + } + + virtual T_channel_type getType() const + { + return channel_x11; + } + + int setBigEndian(int flag); + + // + // Initialize the static members. + // + + static int setReferences(); + + private: + + int handleFastReadRequest(EncodeBuffer &encodeBuffer, const unsigned char &opcode, + const unsigned char *&buffer, const unsigned int &size); + + int handleFastWriteReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + int handleFastWriteEvent(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + // + // Intercept the request before the opcode + // is encoded. + // + + int handleTaintRequest(unsigned char &opcode, const unsigned char *&buffer, + unsigned int &size) + { + if (control -> TaintReplies > 0 && + opcode == X_GetInputFocus) + { + return handleTaintSyncRequest(opcode, buffer, size); + } + + #ifdef LAME + + return handleTaintLameRequest(opcode, buffer, size); + + #endif + + return 0; + } + + int handleTaintLameRequest(unsigned char &opcode, const unsigned char *&buffer, + unsigned int &size); + + int handleTaintSyncRequest(unsigned char &opcode, const unsigned char *&buffer, + unsigned int &size); + + int handleTaintSyncError(unsigned char opcode); + + // + // How to handle sequence counter + // in notification event. + // + + enum T_sequence_mode + { + sequence_immediate, + sequence_deferred + }; + + // + // Send split notifications to the + // agent. + // + + int handleRestart(T_sequence_mode mode, int resource); + + int handleNotify(T_notification_type type, T_sequence_mode mode, + int resource, int request, int position); + + // + // Other utility functions used in + // handling of the image streaming. + // + + int mustSplitMessage(int resource) + { + return (clientStore_ -> getSplitStore(resource) -> + getSize() != 0); + } + + int canSplitMessage(T_split_mode mode, unsigned int size) + { + return ((int) size >= control -> SplitDataThreshold && + (clientStore_ -> getSplitTotalStorageSize() < control -> + SplitTotalStorageSize && clientStore_ -> + getSplitTotalSize() < control -> SplitTotalSize)); + } + + int canSendSplit(Split *split) + { + return (split -> getMode() != split_sync || + split -> getState() == split_missed || + split -> getState() == split_loaded); + } + + int handleSplitSend(EncodeBuffer &encodeBuffer, int resource, + int &total, int &bytes); + + Split *handleSplitFind(T_checksum checksum, int resource); + + int handleSplitChecksum(EncodeBuffer &encodeBuffer, T_checksum checksum); + + void handleSplitPending(int resource) + { + if (splitState_.pending == 0) + { + if (clientStore_ -> getSplitStore(resource) != NULL && + clientStore_ -> getSplitStore(resource) -> + getFirstSplit() != NULL) + { + splitState_.pending = canSendSplit(clientStore_ -> + getSplitStore(resource) -> getFirstSplit()); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitPending: SPLIT! Set the pending " + << "split flag to " << splitState_.pending + << " with " << clientStore_ -> getSplitTotalSize() + << " splits in the split stores.\n" + << logofs_flush; + #endif + } + } + } + + // + // Scan all the split stores to find + // if there is any split to send. + // + + void handleSplitPending(); + + // + // Handle the MIT-SHM initialization + // messages exchanged with the remote + // proxy. + // + + int handleShmemRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + int handleShmemReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + // + // Query the port used to tunnel + // the font server connections. + // + + int handleFontRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + int handleFontReply(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + // + // Let the agent set the cache + // policy for image requests. + // + + int handleCacheRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + // + // Encode the start and end split + // requests. + // + + int handleStartSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + int handleEndSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + // + // Empty a split store and send the + // restart event. + // + + int handleAbortSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + // + // Force the proxy to finalize all + // the pending split operations and + // restart a resource. + // + + int handleFinishSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + // + // Tell the remote peer to send the + // split requests to the X server. + // + + int handleCommitSplitRequest(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + // + // Other utilities. + // + + void handleDecodeCharInfo(DecodeBuffer &, unsigned char *); + + // + // Own read buffer. It is able to identify + // full messages read from the X descriptor. + // + + ClientReadBuffer readBuffer_; + + // + // Sequence number of last request coming + // from the X client or the X server. + // + + unsigned int clientSequence_; + unsigned int serverSequence_; + + // + // Last sequence number known by client. It can + // be the real sequence generated by server or + // the one of the last auto-generated event. + // + + unsigned int lastSequence_; + + // + // Used to identify replies based on sequence + // number of original request. + // + + SequenceQueue sequenceQueue_; + + // + // This is used to test the synchronous flush + // in the proxy. + // + + int lastRequest_; + + // + // Current resource id selected as target and + // other information related to the image split. + // The pending and abort flags are set when we + // want the proxy to give us a chance to send + // more split data. We also save the position + // of the last commit operation performed by + // channel so we can differentially encode the + // position of next message to commit. + // + + typedef struct + { + int resource; + int pending; + int commit; + T_split_mode mode; + + } T_split_state; + + T_split_state splitState_; + + // + // List of agent resources. + // + + List splitResources_; + + // + // How many sync requests we + // have tainted so far. + // + + int taintCounter_; + + private: + + // + // Keep track of object + // creation and deletion. + // + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +#endif /* ClientChannel_H */ diff --git a/nxcomp/src/ClientProxy.cpp b/nxcomp/src/ClientProxy.cpp new file mode 100644 index 000000000..3574d3bf3 --- /dev/null +++ b/nxcomp/src/ClientProxy.cpp @@ -0,0 +1,553 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Socket.h" +#include "Agent.h" + +#include "ClientProxy.h" + +#include "ClientChannel.h" +#include "GenericChannel.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Log the operations related to sending +// and receiving the control tokens. +// + +#undef TOKEN + +ClientProxy::ClientProxy(int proxyFd) : Proxy(proxyFd) +{ + fontServerPort_ = NULL; + + #ifdef DEBUG + *logofs << "ClientProxy: Created new object at " << this + << ".\n" << logofs_flush; + #endif +} + +ClientProxy::~ClientProxy() +{ + delete [] fontServerPort_; + + #ifdef DEBUG + *logofs << "ClientProxy: Deleted object at " << this + << ".\n" << logofs_flush; + #endif +} + +void ClientProxy::handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, + sockaddr * xServerAddr, unsigned int xServerAddrLength) +{ + #ifdef DEBUG + *logofs << "ClientProxy: No display configuration to set.\n" + << logofs_flush; + #endif +} + +void ClientProxy::handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort) +{ + delete [] fontServerPort_; + + fontServerPort_ = new char[strlen(fontServerPort) + 1]; + + strcpy(fontServerPort_, fontServerPort); + + #ifdef DEBUG + *logofs << "ClientProxy: Set port configuration to font '" + << fontServerPort_ << "'.\n" + << logofs_flush; + #endif +} + +int ClientProxy::handleNewConnection(T_channel_type type, int clientFd) +{ + switch (type) + { + case channel_x11: + { + return handleNewXConnection(clientFd); + } + case channel_cups: + { + return handleNewGenericConnection(clientFd, channel_cups, "CUPS"); + } + case channel_smb: + { + return handleNewGenericConnection(clientFd, channel_smb, "SMB"); + } + case channel_media: + { + return handleNewGenericConnection(clientFd, channel_media, "media"); + } + case channel_http: + { + return handleNewGenericConnection(clientFd, channel_http, "HTTP"); + } + case channel_slave: + { + return handleNewSlaveConnection(clientFd); + } + default: + { + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Unsupported channel with type '" + << getTypeName(type) << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unsupported channel with type '" + << getTypeName(type) << "'.\n"; + + return -1; + } + } +} + +int ClientProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId) +{ + switch (type) + { + case channel_font: + { + int port = atoi(fontServerPort_); + + if (port > 0) + { + // + // Connect on the TCP port number. + // + + return handleNewGenericConnectionFromProxyTCP(channelId, channel_font, "localhost", + port, "font"); + } + else + { + // + // Connect to the Unix path. + // + + return handleNewGenericConnectionFromProxyUnix(channelId, channel_font, + fontServerPort_, "font"); + } + } + case channel_slave: + { + return handleNewSlaveConnectionFromProxy(channelId); + } + default: + { + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Unsupported channel with type '" + << getTypeName(type) << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unsupported channel with type '" + << getTypeName(type) << "'.\n"; + + return -1; + } + } +} + +int ClientProxy::handleNewAgentConnection(Agent *agent) +{ + int clientFd = agent -> getLocalFd(); + + int channelId = allocateChannelMap(clientFd); + + if (channelId == -1) + { + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Maximum number of available " + << "channels exceeded.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Maximum number of available " + << "channels exceeded.\n"; + + return -1; + } + + transports_[channelId] = agent -> getTransport(); + + agent_ = channelId; + + return handleNewXConnection(clientFd); +} + +int ClientProxy::handleNewXConnection(int clientFd) +{ + int channelId = getChannel(clientFd); + + // + // Check if the channel has been + // already mapped. + // + + if (channelId == -1) + { + channelId = allocateChannelMap(clientFd); + + if (channelId == -1) + { + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Maximum number of available " + << "channels exceeded.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Maximum number of available " + << "channels exceeded.\n"; + + return -1; + } + } + + #ifdef TEST + *logofs << "ClientProxy: X client descriptor FD#" << clientFd + << " mapped to channel ID#" << channelId << ".\n" + << logofs_flush; + #endif + + // + // Turn queuing off for path proxy-to-X-client. + // + + if (control -> OptionClientNoDelay == 1) + { + SetNoDelay(clientFd, control -> OptionClientNoDelay); + } + + // + // If requested, set the size of the TCP send + // and receive buffers. + // + + if (control -> OptionClientSendBuffer != -1) + { + SetSendBuffer(clientFd, control -> OptionClientSendBuffer); + } + + if (control -> OptionClientReceiveBuffer != -1) + { + SetReceiveBuffer(clientFd, control -> OptionClientReceiveBuffer); + } + + if (allocateTransport(clientFd, channelId) < 0) + { + return -1; + } + + // + // Starting from protocol level 3 client and server + // caches are created in proxy and shared between all + // channels. If remote proxy has older protocol level + // pointers are NULL and channels must create their + // own instances. + // + + channels_[channelId] = new ClientChannel(transports_[channelId], compressor_); + + if (channels_[channelId] == NULL) + { + deallocateTransport(channelId); + + return -1; + } + + increaseChannels(channelId); + + // + // Propagate channel stores and caches to the new + // channel. + // + + channels_[channelId] -> setOpcodes(opcodeStore_); + + channels_[channelId] -> setStores(clientStore_, serverStore_); + + channels_[channelId] -> setCaches(clientCache_, serverCache_); + + int port = atoi(fontServerPort_); + + if (port > 0 || *fontServerPort_ != '\0') + { + channels_[channelId] -> setPorts(1); + } + + if (handleControl(code_new_x_connection, channelId) < 0) + { + return -1; + } + + // + // Let channel configure itself according + // to control parameters. + // + + channels_[channelId] -> handleConfiguration(); + + return 1; +} + +int ClientProxy::handleNewXConnectionFromProxy(int channelId) +{ + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Can't create a new X channel " + << "with ID#" << channelId << " at this side.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't create a new X channel " + << "with ID#" << channelId << " at this side.\n"; + + return -1; +} + +int ClientProxy::handleLoad(T_load_type type) +{ + int channelCount = getChannels(channel_x11); + + if ((channelCount == 0 && type == load_if_first) || + (channelCount > 0 && type == load_if_any)) + { + #ifdef TEST + *logofs << "ClientProxy: Going to load content of client store.\n" + << logofs_flush; + #endif + + int result = handleLoadStores(); + + if (result == 1) + { + if (handleControl(code_load_request) < 0) + { + return -1; + } + + priority_ = 1; + } + else if (result < 0) + { + #ifdef WARNING + *logofs << "ClientProxy: WARNING! Failed to load content " + << "of persistent cache.\n" << logofs_flush; + #endif + + // + // Don't abort the proxy connection in the case + // of a corrupted cache. By not sending the load + // message to the remote peer, both sides will + // start encoding messages using empty stores. + // This behaviour is compatible with old proxy + // versions. + // + + if (channelCount == 0 && type == load_if_first) + { + if (handleResetStores() < 0) + { + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Failed to reset message stores.\n" + << logofs_flush; + #endif + + return -1; + } + } + else + { + return -1; + } + } + } + else + { + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Can't load the stores with " + << channelCount << " remaining channels.\n" + << logofs_flush; + #endif + + return -1; + } + + return 1; +} + +int ClientProxy::handleSave() +{ + // + // If no more X channels are remaining + // then save content of message stores. + // + + int channelCount = getChannels(channel_x11); + + if (channelCount == 0) + { + int result = handleSaveStores(); + + if (result == 1) + { + if (handleControl(code_save_request) < 0) + { + return -1; + } + + priority_ = 1; + + return 1; + } + else if (result < 0) + { + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Failed to save stores " + << "to persistent cache.\n" << logofs_flush; + #endif + + return -1; + } + } + else + { + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Can't save the stores with " + << channelCount << " remaining channels.\n" + << logofs_flush; + #endif + + return -1; + } + + return 1; +} + +int ClientProxy::handleAsyncEvents() +{ + if (canRead() == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: WARNING! Reading while writing " + << "with data available on the proxy link.\n" + << logofs_flush; + #endif + + if (handleRead() < 0) + { + return -1; + } + + return 1; + } + + return 0; +} + +int ClientProxy::handleLoadFromProxy() +{ + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Invalid load control message " + << "received in proxy.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid load control message " + << "received in proxy.\n"; + + return -1; +} + +int ClientProxy::handleSaveFromProxy() +{ + #ifdef PANIC + *logofs << "ClientProxy: PANIC! Invalid save control message " + << "received in proxy.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid save control message " + << "received in proxy.\n"; + + return -1; +} + +int ClientProxy::handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient) const +{ + if (clientStore_ -> saveRequestStores(cachefs, md5StateStream, md5StateClient, + use_checksum, discard_data) < 0) + { + return -1; + } + else if (serverStore_ -> saveReplyStores(cachefs, md5StateStream, md5StateClient, + discard_checksum, use_data) < 0) + { + return -1; + } + else if (serverStore_ -> saveEventStores(cachefs, md5StateStream, md5StateClient, + discard_checksum, use_data) < 0) + { + return -1; + } + + return 1; +} + +int ClientProxy::handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const +{ + if (clientStore_ -> loadRequestStores(cachefs, md5StateStream, + use_checksum, discard_data) < 0) + { + return -1; + } + else if (serverStore_ -> loadReplyStores(cachefs, md5StateStream, + discard_checksum, use_data) < 0) + { + return -1; + } + else if (serverStore_ -> loadEventStores(cachefs, md5StateStream, + discard_checksum, use_data) < 0) + { + return -1; + } + + return 1; +} + diff --git a/nxcomp/src/ClientProxy.h b/nxcomp/src/ClientProxy.h new file mode 100644 index 000000000..b89785b1a --- /dev/null +++ b/nxcomp/src/ClientProxy.h @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ClientProxy_H +#define ClientProxy_H + +#include "Proxy.h" + +// +// Set the verbosity level. +// + +#undef TEST +#undef DEBUG + +class ClientProxy : public Proxy +{ + public: + + ClientProxy(int proxyFD); + + virtual ~ClientProxy(); + + virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, + sockaddr *xServerAddr, unsigned int xServerAddrLength); + + virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort); + + protected: + + // + // Create a new channel. + // + + virtual int handleNewConnection(T_channel_type type, int clientFd); + + virtual int handleNewConnectionFromProxy(T_channel_type type, int channelId); + + virtual int handleNewAgentConnection(Agent *agent); + + virtual int handleNewXConnection(int clientFd); + + virtual int handleNewXConnectionFromProxy(int channelId); + + // + // Implement persistence according + // to our proxy mode. + // + + virtual int handleLoad(T_load_type type); + virtual int handleSave(); + + virtual int handleAsyncEvents(); + + virtual int handleLoadFromProxy(); + virtual int handleSaveFromProxy(); + + virtual int handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient) const; + + virtual int handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const; + + // + // Utility function used to realize + // a new connection. + // + + protected: + + virtual int checkLocalChannelMap(int channelId) + { + // Since ProtoStep7 (#issue 108) + return ((channelId & control -> ChannelMask) != 0); + } + + // + // Ports where to forward extended services' + // TCP connections. + // + + private: + + char *fontServerPort_; +}; + + +#endif /* ClientProxy_H */ diff --git a/nxcomp/src/ClientReadBuffer.cpp b/nxcomp/src/ClientReadBuffer.cpp new file mode 100644 index 000000000..c8f4f69a4 --- /dev/null +++ b/nxcomp/src/ClientReadBuffer.cpp @@ -0,0 +1,178 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ClientReadBuffer.h" + +#include "ClientChannel.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +unsigned int ClientReadBuffer::suggestedLength(unsigned int pendingLength) +{ + // + // Even if the pending data is not + // enough to make a complete message, + // resize the buffer to accommodate + // it all. + // + + unsigned int readLength = pendingLength; + + if (pendingLength < remaining_) + { + readLength = remaining_; + } + + return readLength; +} + +int ClientReadBuffer::locateMessage(const unsigned char *start, + const unsigned char *end, + unsigned int &controlLength, + unsigned int &dataLength, + unsigned int &trailerLength) +{ + unsigned int size = end - start; + + #ifdef TEST + *logofs << "ClientReadBuffer: Locating message for FD#" + << transport_ -> fd() << " with " << size + << " bytes.\n" << logofs_flush; + #endif + + if (firstMessage_) + { + if (size < 12) + { + remaining_ = 12 - size; + + #ifdef TEST + *logofs << "ClientReadBuffer: No message was located " + << "with remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + + if (*start == 0x42) + { + bigEndian_ = 1; + } + else + { + bigEndian_ = 0; + } + + channel_ -> setBigEndian(bigEndian_); + + dataLength = 12 + RoundUp4(GetUINT(start + 6, bigEndian_)) + + RoundUp4(GetUINT(start + 8, bigEndian_)); + + // + // Send the data immediately if this is unlikely + // to be a X connection attempt. + // + + if (dataLength > 4096) + { + #ifdef WARNING + *logofs << "ClientReadBuffer: WARNING! Flushing suspicious X " + << "connection with first request of " << dataLength + << " bytes.\n" << logofs_flush; + #endif + + dataLength = size; + } + } + else + { + if (size < 4) + { + remaining_ = 4 - size; + + #ifdef TEST + *logofs << "ClientReadBuffer: No message was located " + << "with remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + + dataLength = (GetUINT(start + 2, bigEndian_) << 2); + + if (dataLength < 4) + { + #ifdef TEST + *logofs << "ClientReadBuffer: WARNING! Assuming length 4 " + << "for suspicious message of length " << dataLength + << ".\n" << logofs_flush; + #endif + + dataLength = 4; + } + } + + #ifdef TEST + *logofs << "ClientReadBuffer: Length of the next message is " + << dataLength << ".\n" << logofs_flush; + #endif + + if (size < dataLength) + { + remaining_ = dataLength - size; + + #ifdef TEST + *logofs << "ClientReadBuffer: No message was located " + << "with remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + + firstMessage_ = 0; + + controlLength = 0; + trailerLength = 0; + + remaining_ = 0; + + #ifdef TEST + *logofs << "ClientReadBuffer: Located message with " + << "remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 1; +} diff --git a/nxcomp/src/ClientReadBuffer.h b/nxcomp/src/ClientReadBuffer.h new file mode 100644 index 000000000..c557417fa --- /dev/null +++ b/nxcomp/src/ClientReadBuffer.h @@ -0,0 +1,65 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ClientReadBuffer_H +#define ClientReadBuffer_H + +#include "Control.h" +#include "ReadBuffer.h" + +class ClientChannel; + +class ClientReadBuffer : public ReadBuffer +{ + public: + + ClientReadBuffer(Transport *transport, ClientChannel *channel) + + : ReadBuffer(transport), firstMessage_(1), channel_(channel) + { + } + + virtual ~ClientReadBuffer() + { + } + + protected: + + virtual unsigned int suggestedLength(unsigned int pendingLength); + + virtual int locateMessage(const unsigned char *start, + const unsigned char *end, + unsigned int &controlLength, + unsigned int &dataLength, + unsigned int &trailerLength); + + int bigEndian_; + + int firstMessage_; + + ClientChannel *channel_; +}; + +#endif /* ClientReadBuffer_H */ diff --git a/nxcomp/src/ClientStore.cpp b/nxcomp/src/ClientStore.cpp new file mode 100644 index 000000000..0c12eefd8 --- /dev/null +++ b/nxcomp/src/ClientStore.cpp @@ -0,0 +1,226 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ClientStore.h" + +// +// Cached request classes. +// + +#include "ChangeProperty.h" +#include "SendEvent.h" +#include "CreateGC.h" +#include "ChangeGC.h" +#include "CreatePixmap.h" +#include "SetClipRectangles.h" +#include "CopyArea.h" +#include "PolyLine.h" +#include "PolySegment.h" +#include "PolyFillRectangle.h" +#include "PutImage.h" +#include "TranslateCoords.h" +#include "GetImage.h" +#include "ClearArea.h" +#include "ConfigureWindow.h" +#include "ShapeExtension.h" +#include "RenderExtension.h" +#include "PolyText8.h" +#include "PolyText16.h" +#include "ImageText8.h" +#include "ImageText16.h" +#include "PolyPoint.h" +#include "PolyFillArc.h" +#include "PolyArc.h" +#include "FillPoly.h" +#include "InternAtom.h" +#include "GetProperty.h" +#include "SetUnpackGeometry.h" +#include "SetUnpackColormap.h" +#include "SetUnpackAlpha.h" +#include "PutPackedImage.h" +#include "GenericRequest.h" + +// +// Set the verbosity level. +// + +#define WARNING +#define PANIC +#undef TEST + +ClientStore::ClientStore(StaticCompressor *compressor) + + : compressor_(compressor) +{ + if (logofs == NULL) + { + logofs = &cout; + } + + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + requests_[i] = NULL; + } + + requests_[X_ChangeProperty] = new ChangePropertyStore(); + requests_[X_SendEvent] = new SendEventStore(); + requests_[X_CreateGC] = new CreateGCStore(); + requests_[X_SetClipRectangles] = new SetClipRectanglesStore(); + requests_[X_CopyArea] = new CopyAreaStore(); + requests_[X_PolyLine] = new PolyLineStore(); + requests_[X_PolySegment] = new PolySegmentStore(); + requests_[X_PolyFillRectangle] = new PolyFillRectangleStore(); + requests_[X_PutImage] = new PutImageStore(compressor); + requests_[X_TranslateCoords] = new TranslateCoordsStore(); + requests_[X_GetImage] = new GetImageStore(); + requests_[X_ClearArea] = new ClearAreaStore(); + requests_[X_ConfigureWindow] = new ConfigureWindowStore(); + requests_[X_PolyText8] = new PolyText8Store(); + requests_[X_PolyText16] = new PolyText16Store(); + requests_[X_ImageText8] = new ImageText8Store(); + requests_[X_ImageText16] = new ImageText16Store(); + requests_[X_PolyPoint] = new PolyPointStore(); + requests_[X_PolyFillArc] = new PolyFillArcStore(); + requests_[X_PolyArc] = new PolyArcStore(); + requests_[X_FillPoly] = new FillPolyStore(); + requests_[X_InternAtom] = new InternAtomStore(); + requests_[X_GetProperty] = new GetPropertyStore(); + + requests_[X_NXInternalShapeExtension] = new ShapeExtensionStore(compressor); + requests_[X_NXInternalGenericRequest] = new GenericRequestStore(compressor); + requests_[X_NXInternalRenderExtension] = new RenderExtensionStore(compressor); + requests_[X_NXSetUnpackGeometry] = new SetUnpackGeometryStore(compressor); + requests_[X_NXPutPackedImage] = new PutPackedImageStore(compressor); + + // Since ProtoStep7 (#issue 108) + requests_[X_ChangeGC] = new ChangeGCStore(); + requests_[X_CreatePixmap] = new CreatePixmapStore(); + requests_[X_NXSetUnpackColormap] = new SetUnpackColormapStore(compressor); + requests_[X_NXSetUnpackAlpha] = new SetUnpackAlphaStore(compressor); + + for (int i = 0; i < CHANNEL_STORE_RESOURCE_LIMIT; i++) + { + splits_[i] = NULL; + } + + commits_ = new CommitStore(compressor); +} + +ClientStore::~ClientStore() +{ + if (logofs == NULL) + { + logofs = &cout; + } + + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + delete requests_[i]; + } + + for (int i = 0; i < CHANNEL_STORE_RESOURCE_LIMIT; i++) + { + delete splits_[i]; + } + + delete commits_; +} + +int ClientStore::saveRequestStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient, T_checksum_action checksumAction, + T_data_action dataAction) const +{ + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + if (requests_[i] != NULL && + requests_[i] -> saveStore(cachefs, md5StateStream, md5StateClient, + checksumAction, dataAction, + storeBigEndian()) < 0) + { + #ifdef WARNING + *logofs << "ClientStore: WARNING! Error saving request store " + << "for OPCODE#" << (unsigned int) i << ".\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Error saving request store " + << "for opcode '" << (unsigned int) i << "'.\n"; + + return -1; + } + } + + return 1; +} + +int ClientStore::loadRequestStores(istream *cachefs, md5_state_t *md5StateStream, + T_checksum_action checksumAction, T_data_action dataAction) const +{ + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + if (requests_[i] != NULL && + requests_[i] -> loadStore(cachefs, md5StateStream, + checksumAction, dataAction, + storeBigEndian()) < 0) + { + #ifdef WARNING + *logofs << "ClientStore: WARNING! Error loading request store " + << "for OPCODE#" << (unsigned int) i << ".\n" + << logofs_flush; + #endif + + return -1; + } + } + + return 1; +} + +void ClientStore::dumpSplitStores() const +{ + for (int i = 0; i < CHANNEL_STORE_RESOURCE_LIMIT; i++) + { + if (splits_[i] != NULL) + { + splits_[i] -> dump(); + } + } + + if ((getSplitTotalSize() != 0 && getSplitTotalStorageSize() == 0) || + (getSplitTotalSize() == 0 && getSplitTotalStorageSize() != 0)) + { + #ifdef PANIC + *logofs << "ClientStore: PANIC! Inconsistency detected " + << "while handling the split stores.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } +} diff --git a/nxcomp/src/ClientStore.h b/nxcomp/src/ClientStore.h new file mode 100644 index 000000000..009d87d9f --- /dev/null +++ b/nxcomp/src/ClientStore.h @@ -0,0 +1,143 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ClientStore_H +#define ClientStore_H + +#include "Message.h" +#include "Split.h" + +#include "ChannelStore.h" + +class StaticCompressor; + +class ClientStore : public ChannelStore +{ + public: + + ClientStore(StaticCompressor *compressor); + + virtual ~ClientStore(); + + // + // Get the store based on the index. + // + + MessageStore *getRequestStore(unsigned char opcode) const + { + return requests_[opcode]; + } + + SplitStore *getSplitStore(int resource) const + { + return splits_[resource]; + } + + int getSplitTotalSize() const + { + return SplitStore::getTotalSize(); + } + + int getSplitTotalStorageSize() const + { + return SplitStore::getTotalStorageSize(); + } + + CommitStore *getCommitStore() const + { + return commits_; + } + + int getCommitSize() const + { + return commits_ -> getSize(); + } + + void dumpSplitStore(int resource) const + { + splits_[resource] -> dump(); + } + + void dumpCommitStore() const + { + commits_ -> dump(); + } + + void dumpSplitStores() const; + + SplitStore *createSplitStore(int resource) + { + splits_[resource] = new SplitStore(compressor_, commits_, resource); + + return splits_[resource]; + } + + void destroySplitStore(int resource) + { + delete splits_[resource]; + + splits_[resource] = NULL; + } + + // + // Actually save the message store + // to disk according to proxy mode. + // + + int saveRequestStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient, T_checksum_action checksumAction, + T_data_action dataAction) const; + + int loadRequestStores(istream *cachefs, md5_state_t *md5StateStream, + T_checksum_action checksumAction, T_data_action dataAction) const; + + private: + + // + // A client store contains requests. + // + + MessageStore *requests_[CHANNEL_STORE_OPCODE_LIMIT]; + + // + // Client messages being split. + // + + SplitStore *splits_[CHANNEL_STORE_RESOURCE_LIMIT]; + + // + // Messages having been recomposed. + // + + CommitStore *commits_; + + // + // Passed forward to the other stores. + // + + StaticCompressor *compressor_; +}; + +#endif /* ClientStore_H */ diff --git a/nxcomp/src/Colormap.cpp b/nxcomp/src/Colormap.cpp new file mode 100644 index 000000000..afe99ecae --- /dev/null +++ b/nxcomp/src/Colormap.cpp @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "Unpack.h" +#include "Colormap.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int UnpackColormap(unsigned char method, unsigned char *src_data, int src_size, + unsigned char *dst_data, int dst_size) +{ + if (*src_data == 0) + { + if (dst_size != src_size - 1) + { + #ifdef TEST + *logofs << "UnpackColormap: PANIC! Invalid destination size " + << dst_size << " with source " << src_size + << ".\n" << logofs_flush; + #endif + + return -1; + } + + #ifdef TEST + *logofs << "UnpackColormap: Expanding " << src_size - 1 + << " bytes of plain colormap data.\n" << logofs_flush; + #endif + + memcpy(dst_data, src_data + 1, src_size - 1); + + return 1; + } + + unsigned int check_size = dst_size; + + int result = ZDecompress(&unpackStream, dst_data, &check_size, + src_data + 1, src_size - 1); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "UnpackColormap: PANIC! Failure decompressing colormap data. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decompressing colormap data. " + << "Error is '" << zError(result) << "'.\n"; + + return -1; + } + else if (check_size != (unsigned int) dst_size) + { + #ifdef PANIC + *logofs << "UnpackColormap: PANIC! Size mismatch in colormap data. " + << "Resulting size is " << check_size << " with " + << "expected size " << dst_size << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Size mismatch in colormap data. " + << "Resulting size is " << check_size << " with " + << "expected size " << dst_size << ".\n"; + + return -1; + } + + #ifdef TEST + *logofs << "UnpackColormap: Decompressed " << src_size - 1 + << " bytes to " << dst_size << " bytes of colormap data.\n" + << logofs_flush; + #endif + + return 1; +} diff --git a/nxcomp/src/Colormap.h b/nxcomp/src/Colormap.h new file mode 100644 index 000000000..a96d003fa --- /dev/null +++ b/nxcomp/src/Colormap.h @@ -0,0 +1,32 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Colormap_H +#define Colormap_H + +int UnpackColormap(unsigned char method, unsigned char *src_data, int src_size, + unsigned char *dst_data, int dst_size); + +#endif /* Colormap_H */ diff --git a/nxcomp/src/ConfigureWindow.cpp b/nxcomp/src/ConfigureWindow.cpp new file mode 100644 index 000000000..32d3153b9 --- /dev/null +++ b/nxcomp/src/ConfigureWindow.cpp @@ -0,0 +1,142 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ConfigureWindow.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int ConfigureWindowStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ConfigureWindowMessage *configureWindow = (ConfigureWindowMessage *) message; + + // + // Here is the fingerprint. + // + + configureWindow -> window = GetULONG(buffer + 4, bigEndian); + + configureWindow -> value_mask = GetUINT(buffer + 8, bigEndian); + + // + // To increase effectiveness of the caching algorithm + // we remove the unused bytes carried in the data part. + // + + if ((int) size > dataOffset) + { + #ifdef DEBUG + *logofs << name() << ": Removing unused bytes from the data payload.\n" << logofs_flush; + #endif + + configureWindow -> value_mask &= (1 << 7) - 1; + + unsigned int mask = 0x1; + unsigned char *source = (unsigned char *) buffer + CONFIGUREWINDOW_DATA_OFFSET; + unsigned long value = 0; + + for (unsigned int i = 0; i < 7; i++) + { + if (configureWindow -> value_mask & mask) + { + value = GetULONG(source, bigEndian); + + value &= (1 << CONFIGUREWINDOW_FIELD_WIDTH[i]) - 1; + + PutULONG(value, source, bigEndian); + + source += 4; + } + mask <<= 1; + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int ConfigureWindowStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ConfigureWindowMessage *configureWindow = (ConfigureWindowMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(configureWindow -> window, buffer + 4, bigEndian); + + PutUINT(configureWindow -> value_mask, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void ConfigureWindowStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + ConfigureWindowMessage *configureWindow = (ConfigureWindowMessage *) message; + + *logofs << "ConfigureWindow: window " << configureWindow -> window + << ", value_mask " << configureWindow -> value_mask + << ", size " << configureWindow -> size_ << ".\n"; + + #endif +} + +void ConfigureWindowStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 4, 4); + md5_append(md5_state_, buffer + 8, 2); +} diff --git a/nxcomp/src/ConfigureWindow.h b/nxcomp/src/ConfigureWindow.h new file mode 100644 index 000000000..e02c2aae1 --- /dev/null +++ b/nxcomp/src/ConfigureWindow.h @@ -0,0 +1,178 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ConfigureWindow_H +#define ConfigureWindow_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define CONFIGUREWINDOW_ENABLE_CACHE 1 +#define CONFIGUREWINDOW_ENABLE_DATA 0 +#define CONFIGUREWINDOW_ENABLE_SPLIT 0 +#define CONFIGUREWINDOW_ENABLE_COMPRESS 0 + +#define CONFIGUREWINDOW_DATA_LIMIT 32 +#define CONFIGUREWINDOW_DATA_OFFSET 12 + +#define CONFIGUREWINDOW_CACHE_SLOTS 3000 +#define CONFIGUREWINDOW_CACHE_THRESHOLD 5 +#define CONFIGUREWINDOW_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class ConfigureWindowMessage : public Message +{ + friend class ConfigureWindowStore; + + public: + + ConfigureWindowMessage() + { + } + + ~ConfigureWindowMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int window; + unsigned short value_mask; +}; + +class ConfigureWindowStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + ConfigureWindowStore() : MessageStore() + { + enableCache = CONFIGUREWINDOW_ENABLE_CACHE; + enableData = CONFIGUREWINDOW_ENABLE_DATA; + enableSplit = CONFIGUREWINDOW_ENABLE_SPLIT; + enableCompress = CONFIGUREWINDOW_ENABLE_COMPRESS; + + dataLimit = CONFIGUREWINDOW_DATA_LIMIT; + dataOffset = CONFIGUREWINDOW_DATA_OFFSET; + + cacheSlots = CONFIGUREWINDOW_CACHE_SLOTS; + cacheThreshold = CONFIGUREWINDOW_CACHE_THRESHOLD; + cacheLowerThreshold = CONFIGUREWINDOW_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~ConfigureWindowStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "ConfigureWindow"; + } + + virtual unsigned char opcode() const + { + return X_ConfigureWindow; + } + + virtual unsigned int storage() const + { + return sizeof(ConfigureWindowMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new ConfigureWindowMessage(); + } + + virtual Message *create(const Message &message) const + { + return new ConfigureWindowMessage((const ConfigureWindowMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (ConfigureWindowMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* ConfigureWindow_H */ diff --git a/nxcomp/src/Control.cpp b/nxcomp/src/Control.cpp new file mode 100644 index 000000000..75fd56e3f --- /dev/null +++ b/nxcomp/src/Control.cpp @@ -0,0 +1,822 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "NX.h" +#include "NXpack.h" + +#include "Control.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Flush immediately on prioritized messages. +// + +#define FLUSH_PRIORITY 0 + +// +// Maximum number of bytes sent for each token. +// + +#define TOKEN_SIZE 1536 + +// +// Maximum number of tokens that can be spent +// by the client proxy before having to block +// waiting for a token reply. +// + +#define TOKEN_LIMIT 24 + +// +// By default assume the proxy is running as a +// standalone program. +// + +#define LINK_ENCRYPTED 0 + +// +// Maximum number of pids the proxy will record +// and kill at shutdown. +// + +#define KILL_LIMIT 16 + +// +// Allocate on the NX client side channels whose +// ids are a multiple of 8 (starting from 0). All +// the other ids can be used to allocate channels +// at the NX server side (X client side). +// + +#define CHANNEL_MASK 0x07 + +// +// Kill session if control parameters cannot be +// negotiated before this timeout. +// + +#define INIT_TIMEOUT 60000 + +// +// Enter the congestion state if the remote does +// not reply to a ping within the given amount +// of time. +// + +#define PING_TIMEOUT 5000 + +// +// Only send one motion event any N milliseconds. +// + +#define MOTION_TIMEOUT 0 + + +// +// Force an update of the congestion counter if +// the proxy is idle for this time. +// + +#define IDLE_TIMEOUT 50 + +// +// Close X connection if can't write before this +// timeout. +// + +#define CHANNEL_TIMEOUT 10000 + +// +// Warn user (or close proxy connection) if don't +// receive any data before this timeout. +// + +#define PROXY_TIMEOUT 120000 + +// +// How many milliseconds to wait for the shared +// memory completion event to become available. +// + +#define SHMEM_TIMEOUT 200 +// +// Before closing down the proxy, wait for the +// given amount of miliseconds to let all the +// running applications to close down their +// connections. +// +// A null timeout will cause the proxy to wait +// indefinitely, until the watchdog process is +// killed. This is usually the way the proxy is +// started by the NX server. If on the other +// hand a timeout is given and there no channel +// is remaining, the proxy will be closed down +// using a small timeout, presently of 500 ms. +// + +#define CLEANUP_TIMEOUT 3000 + +// +// Wait this amount of milliseconds after any +// iteration of the house-keeping process. +// + +#define KEEPER_TIMEOUT 60000 + +// +// In case of timeout, select can return control +// to program earlier or later of this amount of +// ms. Consider this when calculating if timeout +// is elapsed. +// + +#define LATENCY_TIMEOUT 1 + +// +// Control memory allocation in transport +// and other classes. +// + +#define TRANSPORT_X_BUFFER_SIZE 131072 +#define TRANSPORT_PROXY_BUFFER_SIZE 65536 +#define TRANSPORT_GENERIC_BUFFER_SIZE 16384 + +#define TRANSPORT_X_BUFFER_THRESHOLD 262144 +#define TRANSPORT_PROXY_BUFFER_THRESHOLD 131072 +#define TRANSPORT_GENERIC_BUFFER_THRESHOLD 32768 + +// +// Never allow buffers to exceed this limit. +// + +#define TRANSPORT_MAXIMUM_BUFFER_SIZE 393216 + +// +// Immediately flush the accumulated data to +// the X server if the write buffer exceeds +// this size. +// + +#define TRANSPORT_FLUSH_BUFFER_SIZE 16384 + +// +// Defaults used for socket options. +// + +#define OPTION_PROXY_KEEP_ALIVE 0 +#define OPTION_PROXY_LOW_DELAY 1 +#define OPTION_PROXY_CLIENT_NO_DELAY 1 +#define OPTION_PROXY_SERVER_NO_DELAY 1 +#define OPTION_CLIENT_NO_DELAY 1 +#define OPTION_SERVER_NO_DELAY 1 + +#define OPTION_PROXY_RECEIVE_BUFFER -1 +#define OPTION_CLIENT_RECEIVE_BUFFER -1 +#define OPTION_SERVER_RECEIVE_BUFFER -1 + +#define OPTION_PROXY_SEND_BUFFER -1 +#define OPTION_CLIENT_SEND_BUFFER -1 +#define OPTION_SERVER_SEND_BUFFER -1 + +#define OPTION_PROXY_RETRY_CONNECT 30 +#define OPTION_PROXY_RETRY_ACCEPT 3 +#define OPTION_SERVER_RETRY_CONNECT 3 + +// +// Defaults used for cache persistence. +// + +#define PERSISTENT_CACHE_THRESHOLD 102400 + +#define PERSISTENT_CACHE_ENABLE_LOAD 1 +#define PERSISTENT_CACHE_ENABLE_SAVE 1 + +#define PERSISTENT_CACHE_CHECK_ON_SHUTDOWN 0 + +#define PERSISTENT_CACHE_LOAD_PACKED 1 +#define PERSISTENT_CACHE_LOAD_RENDER 1 + +#define PERSISTENT_CACHE_DISK_LIMIT 33554432 + +// +// Defaults used for image cache. +// + +#define IMAGE_CACHE_ENABLE_LOAD 0 +#define IMAGE_CACHE_ENABLE_SAVE 0 + +#define IMAGE_CACHE_DISK_LIMIT 33554432 + +// +// Suggested defaults for read length parameters +// used by read buffer classes. +// + +#define CLIENT_INITIAL_READ_SIZE 8192 +#define CLIENT_MAXIMUM_BUFFER_SIZE 262144 + +#define SERVER_INITIAL_READ_SIZE 8192 +#define SERVER_MAXIMUM_BUFFER_SIZE 65536 + +#define PROXY_INITIAL_READ_SIZE 65536 +#define PROXY_MAXIMUM_BUFFER_SIZE 262144 + 1024 + +#define GENERIC_INITIAL_READ_SIZE 8192 +#define GENERIC_MAXIMUM_BUFFER_SIZE 8192 + +// +// Calculate bitrate in given time frames. +// Values are in milliseconds. +// + +#define SHORT_BITRATE_TIME_FRAME 5000 +#define LONG_BITRATE_TIME_FRAME 30000 + +// +// Bandwidth control. A value of 0 means no +// limit. Values are stored internally in +// bytes per second. +// + +#define CLIENT_BITRATE_LIMIT 0 +#define SERVER_BITRATE_LIMIT 0 + +// +// Default values for cache control. We limit +// the maximum size of a request to 262144 but +// we need to consider the replies, whose size +// may be up to 4MB. +// + +#define MINIMUM_MESSAGE_SIZE 4 +#define MAXIMUM_MESSAGE_SIZE 4194304 +#define MAXIMUM_REQUEST_SIZE 262144 + +#define CLIENT_TOTAL_STORAGE_SIZE 8388608 +#define SERVER_TOTAL_STORAGE_SIZE 8388608 + +#define STORE_TIME_LIMIT 3600 + +#define STORE_HITS_LOAD_BONUS 10 +#define STORE_HITS_ADD_BONUS 20 +#define STORE_HITS_LIMIT 100 + +#define STORE_HITS_TOUCH 1 +#define STORE_HITS_UNTOUCH 2 + +// +// Default parameters for message splitting. +// + +#define SPLIT_MODE 1 +#define SPLIT_TIMEOUT 50 +#define SPLIT_TOTAL_SIZE 128 +#define SPLIT_TOTAL_STORAGE_SIZE 1048576 +#define SPLIT_DATA_THRESHOLD 65536 +#define SPLIT_DATA_PACKET_LIMIT 24576 + +// +// Agent related parameters. +// + +#define PACK_METHOD 63 +#define PACK_QUALITY 9 +#define HIDE_RENDER 0 +#define TAINT_REPLIES 1 +#define TAINT_THRESHOLD 8 + +// +// In current version only X server support is +// implemented. Note that use of shared memory +// is negotiated according to options provided +// by the user. +// + +#define SHMEM_CLIENT 0 +#define SHMEM_SERVER 1 + +// +// Default size of shared memory segments used +// in MIT-SHM support. +// + +#define SHMEM_CLIENT_SIZE 0 +#define SHMEM_SERVER_SIZE 2097152 + +// +// What do we do at the end of session? If this +// flag is set, we launch a new client letting +// the user run a new NX session. +// + +#define ENABLE_RESTART_ON_SHUTDOWN 0 + +// +// Do we produce a core dump on fatal errors? +// + +#define ENABLE_CORE_DUMP_ON_ABORT 0 + +// +// Reopen the log file if it exceeds this size. +// + +#define FILE_SIZE_LIMIT 60000000 + +// +// Check periodically if we need to truncate the +// log file. By default check every minute. +// + +#define FILE_SIZE_CHECK_TIMEOUT 60000 + +// +// Protocol version compatibility values +// + +const int Control::NX_MIN_PROTO_STEP = 10; +const int Control::NX_MAX_PROTO_STEP = 10; +const char* const Control::NXPROXY_COMPATIBILITY_VERSION = "3.5.0"; + +// +// Set defaults for control. They should be what +// you get in case of 'local' connection. +// + +Control::Control() +{ + ProxyMode = proxy_undefined; + ProxyStage = stage_undefined; + SessionMode = session_undefined; + FlushPolicy = policy_undefined; + LinkMode = link_undefined; + + LinkEncrypted = LINK_ENCRYPTED; + FlushPriority = FLUSH_PRIORITY; + + TokenSize = TOKEN_SIZE; + TokenLimit = TOKEN_LIMIT; + + ChannelMask = CHANNEL_MASK; + + InitTimeout = INIT_TIMEOUT; + PingTimeout = PING_TIMEOUT; + MotionTimeout = MOTION_TIMEOUT; + IdleTimeout = IDLE_TIMEOUT; + + ChannelTimeout = CHANNEL_TIMEOUT; + ProxyTimeout = PROXY_TIMEOUT; + ShmemTimeout = SHMEM_TIMEOUT; + + CleanupTimeout = CLEANUP_TIMEOUT; + KeeperTimeout = KEEPER_TIMEOUT; + LatencyTimeout = LATENCY_TIMEOUT; + + FileSizeLimit = FILE_SIZE_LIMIT; + FileSizeCheckTimeout = FILE_SIZE_CHECK_TIMEOUT; + + EnableRestartOnShutdown = ENABLE_RESTART_ON_SHUTDOWN; + + KillDaemonOnShutdownLimit = KILL_LIMIT; + + KillDaemonOnShutdown = new int[KillDaemonOnShutdownLimit]; + + for (int i = 0; i < KILL_LIMIT; i++) + { + KillDaemonOnShutdown[i] = -1; + } + + KillDaemonOnShutdownNumber = 0; + + EnableCoreDumpOnAbort = ENABLE_CORE_DUMP_ON_ABORT; + + // + // Collect statistics by default. + // + + EnableStatistics = 1; + + // + // Memory restrictions if any. + // + + LocalMemoryLevel = -1; + + // + // Compression must be negotiated between proxies. + // + + LocalDeltaCompression = -1; + RemoteDeltaCompression = -1; + + LocalDataCompression = -1; + LocalStreamCompression = -1; + + RemoteDataCompression = -1; + RemoteStreamCompression = -1; + + LocalDataCompressionLevel = -1; + LocalDataCompressionThreshold = -1; + LocalStreamCompressionLevel = -1; + + RemoteDataCompressionLevel = -1; + RemoteStreamCompressionLevel = -1; + + // + // Transport buffers' allocation parameters. + // + + TransportXBufferSize = TRANSPORT_X_BUFFER_SIZE; + TransportProxyBufferSize = TRANSPORT_PROXY_BUFFER_SIZE; + TransportGenericBufferSize = TRANSPORT_GENERIC_BUFFER_SIZE; + + TransportXBufferThreshold = TRANSPORT_X_BUFFER_THRESHOLD; + TransportProxyBufferThreshold = TRANSPORT_PROXY_BUFFER_THRESHOLD; + TransportGenericBufferThreshold = TRANSPORT_GENERIC_BUFFER_THRESHOLD; + + TransportMaximumBufferSize = TRANSPORT_MAXIMUM_BUFFER_SIZE; + + // + // Flush the write buffer if it exceeds + // this size. + // + + TransportFlushBufferSize = TRANSPORT_FLUSH_BUFFER_SIZE; + + // + // Socket options. + // + + OptionProxyKeepAlive = OPTION_PROXY_KEEP_ALIVE; + OptionProxyLowDelay = OPTION_PROXY_LOW_DELAY; + OptionProxyClientNoDelay = OPTION_PROXY_CLIENT_NO_DELAY; + OptionProxyServerNoDelay = OPTION_PROXY_SERVER_NO_DELAY; + OptionClientNoDelay = OPTION_CLIENT_NO_DELAY; + OptionServerNoDelay = OPTION_SERVER_NO_DELAY; + + OptionProxyReceiveBuffer = OPTION_PROXY_RECEIVE_BUFFER; + OptionClientReceiveBuffer = OPTION_CLIENT_RECEIVE_BUFFER; + OptionServerReceiveBuffer = OPTION_SERVER_RECEIVE_BUFFER; + + OptionProxySendBuffer = OPTION_PROXY_SEND_BUFFER; + OptionClientSendBuffer = OPTION_CLIENT_SEND_BUFFER; + OptionServerSendBuffer = OPTION_SERVER_SEND_BUFFER; + + OptionProxyRetryAccept = OPTION_PROXY_RETRY_ACCEPT; + OptionProxyRetryConnect = OPTION_PROXY_RETRY_CONNECT; + OptionServerRetryConnect = OPTION_SERVER_RETRY_CONNECT; + + // + // Base NX directories. + // + + HomePath = NULL; + RootPath = NULL; + SystemPath = NULL; + TempPath = NULL; + ClientPath = NULL; + + // + // Set defaults for handling persistent cache. + // + + PersistentCachePath = NULL; + PersistentCacheName = NULL; + + PersistentCacheThreshold = PERSISTENT_CACHE_THRESHOLD; + + PersistentCacheEnableLoad = PERSISTENT_CACHE_ENABLE_LOAD; + PersistentCacheEnableSave = PERSISTENT_CACHE_ENABLE_SAVE; + + PersistentCacheCheckOnShutdown = PERSISTENT_CACHE_CHECK_ON_SHUTDOWN; + + PersistentCacheLoadPacked = PERSISTENT_CACHE_LOAD_PACKED; + PersistentCacheLoadRender = PERSISTENT_CACHE_LOAD_RENDER; + + PersistentCacheDiskLimit = PERSISTENT_CACHE_DISK_LIMIT; + + // + // Set defaults for image cache. + // + + ImageCachePath = NULL; + + ImageCacheEnableLoad = IMAGE_CACHE_ENABLE_LOAD; + ImageCacheEnableSave = IMAGE_CACHE_ENABLE_SAVE; + + ImageCacheDiskLimit = IMAGE_CACHE_DISK_LIMIT; + + // + // Set defaults for the read buffers. + // + + ClientInitialReadSize = CLIENT_INITIAL_READ_SIZE; + ClientMaximumBufferSize = CLIENT_MAXIMUM_BUFFER_SIZE; + + ServerInitialReadSize = SERVER_INITIAL_READ_SIZE; + ServerMaximumBufferSize = SERVER_MAXIMUM_BUFFER_SIZE; + + ProxyInitialReadSize = PROXY_INITIAL_READ_SIZE; + ProxyMaximumBufferSize = PROXY_MAXIMUM_BUFFER_SIZE; + + GenericInitialReadSize = GENERIC_INITIAL_READ_SIZE; + GenericMaximumBufferSize = GENERIC_MAXIMUM_BUFFER_SIZE; + + ShortBitrateTimeFrame = SHORT_BITRATE_TIME_FRAME; + LongBitrateTimeFrame = LONG_BITRATE_TIME_FRAME; + + // + // Bandwidth control. + // + + LocalBitrateLimit = -1; + + ClientBitrateLimit = CLIENT_BITRATE_LIMIT; + ServerBitrateLimit = SERVER_BITRATE_LIMIT; + + // + // Default parameters for message handling. + // + + ClientTotalStorageSize = CLIENT_TOTAL_STORAGE_SIZE; + ServerTotalStorageSize = SERVER_TOTAL_STORAGE_SIZE; + + LocalTotalStorageSize = -1; + RemoteTotalStorageSize = -1; + + StoreTimeLimit = STORE_TIME_LIMIT; + + StoreHitsLoadBonus = STORE_HITS_LOAD_BONUS; + StoreHitsAddBonus = STORE_HITS_ADD_BONUS; + StoreHitsLimit = STORE_HITS_LIMIT; + + StoreHitsTouch = STORE_HITS_TOUCH; + StoreHitsUntouch = STORE_HITS_UNTOUCH; + + MinimumMessageSize = MINIMUM_MESSAGE_SIZE; + MaximumMessageSize = MAXIMUM_MESSAGE_SIZE; + MaximumRequestSize = MAXIMUM_REQUEST_SIZE; + + SplitMode = SPLIT_MODE; + SplitTimeout = SPLIT_TIMEOUT; + SplitTotalSize = SPLIT_TOTAL_SIZE; + SplitTotalStorageSize = SPLIT_TOTAL_STORAGE_SIZE; + SplitDataThreshold = SPLIT_DATA_THRESHOLD; + SplitDataPacketLimit = SPLIT_DATA_PACKET_LIMIT; + + PackMethod = PACK_METHOD; + PackQuality = PACK_QUALITY; + HideRender = HIDE_RENDER; + TaintReplies = TAINT_REPLIES; + TaintThreshold = TAINT_THRESHOLD; + + ShmemClient = SHMEM_CLIENT; + ShmemServer = SHMEM_SERVER; + + ShmemClientSize = SHMEM_CLIENT_SIZE; + ShmemServerSize = SHMEM_SERVER_SIZE; + + // + // Get local version number from compile time + // settings. Version of remote proxy will be + // checked at connection time. + // + + RemoteVersionMajor = -1; + RemoteVersionMinor = -1; + RemoteVersionPatch = -1; + RemoteVersionMaintenancePatch = -1; + + CompatVersionMajor = -1; + CompatVersionMinor = -1; + CompatVersionPatch = -1; + CompatVersionMaintenancePatch = -1; + + LocalVersionMajor = NXMajorVersion(); + LocalVersionMinor = NXMinorVersion(); + LocalVersionPatch = NXPatchVersion(); + LocalVersionMaintenancePatch = NXMaintenancePatchVersion(); + + #ifdef TEST + *logofs << "Control: Major version is " << LocalVersionMajor + << " minor is " << LocalVersionMinor << " patch is " + << LocalVersionPatch << " Maintenance version is " + << LocalVersionMaintenancePatch << ".\n" << logofs_flush; + #endif + + // + // Initialize local implemented methods later + // and negotiate remote methods at connection + // time. + // + + LocalUnpackMethods = NULL; + RemoteUnpackMethods = NULL; + + // + // Set to 1 those methods which are implemented. + // + + setLocalUnpackMethods(); + + // + // Set the protocol version at the + // time the session is negotiated. + // + + protoStep_ = 0; +} + +Control::~Control() +{ + if (KillDaemonOnShutdown != NULL) + { + delete [] KillDaemonOnShutdown; + } + + if (HomePath != NULL) + { + delete [] HomePath; + } + + if (RootPath != NULL) + { + delete [] RootPath; + } + + if (SystemPath != NULL) + { + delete [] SystemPath; + } + + if (TempPath != NULL) + { + delete [] TempPath; + } + + if (ClientPath != NULL) + { + delete [] ClientPath; + } + + if (PersistentCachePath != NULL) + { + delete [] PersistentCachePath; + } + + if (PersistentCacheName != NULL) + { + delete [] PersistentCacheName; + } + + if (LocalUnpackMethods != NULL) + { + delete [] LocalUnpackMethods; + } + + if (RemoteUnpackMethods != NULL) + { + delete [] RemoteUnpackMethods; + } + + if (ImageCachePath != NULL) + { + delete [] ImageCachePath; + } +} + +// +// Set the protocol step based on the +// remote version. +// + +void Control::setProtoStep(int step) +{ + if (isValidProtoStep(step)) + { + protoStep_ = step; + } + else + { + #ifdef PANIC + *logofs << "Control: PANIC! Invalid protocol step " + << "with value " << step << ".\n" + << logofs_flush; + #endif + + HandleCleanup(); + } +} + +int Control::getProtoStep() +{ + if (isValidProtoStep(protoStep_)) + { + return protoStep_; + } + else + { + #ifdef PANIC + *logofs << "Control: PANIC! Can't identify the " + << "protocol step.\n" << logofs_flush; + #endif + + HandleCleanup(); + } +} + +// +// Set here the pack/unpack methods that are +// implemented by this NX proxy. +// + +void Control::setLocalUnpackMethods() +{ + LocalUnpackMethods = new unsigned char[PACK_METHOD_LIMIT]; + RemoteUnpackMethods = new unsigned char[PACK_METHOD_LIMIT]; + + for (int i = 0; i < PACK_METHOD_LIMIT; i++) + { + LocalUnpackMethods[i] = 0; + RemoteUnpackMethods[i] = 0; + } + + LocalUnpackMethods[NO_PACK] = 1; + + LocalUnpackMethods[PACK_MASKED_8_COLORS] = 1; + LocalUnpackMethods[PACK_MASKED_64_COLORS] = 1; + LocalUnpackMethods[PACK_MASKED_256_COLORS] = 1; + LocalUnpackMethods[PACK_MASKED_512_COLORS] = 1; + LocalUnpackMethods[PACK_MASKED_4K_COLORS] = 1; + LocalUnpackMethods[PACK_MASKED_32K_COLORS] = 1; + LocalUnpackMethods[PACK_MASKED_64K_COLORS] = 1; + LocalUnpackMethods[PACK_MASKED_256K_COLORS] = 1; + LocalUnpackMethods[PACK_MASKED_2M_COLORS] = 1; + LocalUnpackMethods[PACK_MASKED_16M_COLORS] = 1; + + LocalUnpackMethods[PACK_RAW_8_BITS] = 1; + LocalUnpackMethods[PACK_RAW_16_BITS] = 1; + LocalUnpackMethods[PACK_RAW_24_BITS] = 1; + + LocalUnpackMethods[PACK_COLORMAP_256_COLORS] = 1; + + LocalUnpackMethods[PACK_JPEG_8_COLORS] = 1; + LocalUnpackMethods[PACK_JPEG_64_COLORS] = 1; + LocalUnpackMethods[PACK_JPEG_256_COLORS] = 1; + LocalUnpackMethods[PACK_JPEG_512_COLORS] = 1; + LocalUnpackMethods[PACK_JPEG_4K_COLORS] = 1; + LocalUnpackMethods[PACK_JPEG_32K_COLORS] = 1; + LocalUnpackMethods[PACK_JPEG_64K_COLORS] = 1; + LocalUnpackMethods[PACK_JPEG_256K_COLORS] = 1; + LocalUnpackMethods[PACK_JPEG_2M_COLORS] = 1; + LocalUnpackMethods[PACK_JPEG_16M_COLORS] = 1; + + LocalUnpackMethods[PACK_PNG_8_COLORS] = 1; + LocalUnpackMethods[PACK_PNG_64_COLORS] = 1; + LocalUnpackMethods[PACK_PNG_256_COLORS] = 1; + LocalUnpackMethods[PACK_PNG_512_COLORS] = 1; + LocalUnpackMethods[PACK_PNG_4K_COLORS] = 1; + LocalUnpackMethods[PACK_PNG_32K_COLORS] = 1; + LocalUnpackMethods[PACK_PNG_64K_COLORS] = 1; + LocalUnpackMethods[PACK_PNG_256K_COLORS] = 1; + LocalUnpackMethods[PACK_PNG_2M_COLORS] = 1; + LocalUnpackMethods[PACK_PNG_16M_COLORS] = 1; + + LocalUnpackMethods[PACK_RGB_16M_COLORS] = 1; + LocalUnpackMethods[PACK_RLE_16M_COLORS] = 1; + + LocalUnpackMethods[PACK_ALPHA] = 1; + LocalUnpackMethods[PACK_COLORMAP] = 1; + + LocalUnpackMethods[PACK_BITMAP_16M_COLORS] = 1; +} diff --git a/nxcomp/src/Control.h b/nxcomp/src/Control.h new file mode 100644 index 000000000..764fca2c1 --- /dev/null +++ b/nxcomp/src/Control.h @@ -0,0 +1,764 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Control_H +#define Control_H + +#include "NXpack.h" + +#include "Misc.h" +#include "Types.h" +#include "Timestamp.h" +#include "Statistics.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// This is the mode proxy is running. +// + +typedef enum +{ + proxy_undefined = -1, + proxy_client, + proxy_server, + proxy_last_tag +} +T_proxy_mode; + +// +// Handle advances in the connection +// procedure. +// + +typedef enum +{ + stage_undefined, + stage_initializing, + stage_connecting, + stage_connected, + stage_waiting_forwarder_version, + stage_waiting_forwarder_options, + stage_sending_forwarder_options, + stage_waiting_proxy_version, + stage_waiting_proxy_options, + stage_sending_proxy_options, + stage_waiting_proxy_caches, + stage_sending_proxy_caches, + stage_operational, + stage_terminating, + stage_terminated +} +T_proxy_stage; + +// +// Hint about whether or not the proxy is +// connected to a NX agen. +// + +typedef enum +{ + session_undefined = -1, + session_agent, + session_shadow, + session_proxy, + session_last_tag +} +T_session_mode; + +// +// Set how data will be written to the peer +// socket. +// + +typedef enum +{ + policy_undefined = -1, + policy_immediate, + policy_deferred +} +T_flush_policy; + +// +// Link mode, after negotiation, will be set to +// any of the values defined in the NXproto.h. +// + +#define link_undefined -1; + +// +// This class collects functioning parameters, +// to be configurable at run-time. They are for +// the most part regarding timeouts, transport +// and message stores handling. +// + +class Control +{ + public: + + // + // Does proxy run in client mode or server mode? + // As soon as we'll have gone through parsing of + // the command line options the current mode will + // be propagated to the control class. + // + + T_proxy_mode ProxyMode; + + // + // Goes from initializing to operational. + // + + T_proxy_stage ProxyStage; + + // + // Hint about type of session currently running. + // + + T_session_mode SessionMode; + + // + // Either immediate or defferred flushes. + // + + T_flush_policy FlushPolicy; + + // + // If set, the channels will try to flush the + // encoded data whenever there is a prioritized + // message. Depending on the flush policy, this + // may determine an immediate flush or an event + // being generated telling to the agent that it + // should flush the proxy link. + // + + int FlushPriority; + + // + // Id corresponding to link speed negotiated + // between proxies. + // + + int LinkMode; + + // + // Set if the proxy is connected to a program + // providing the encryption of the point to + // point communication. + // + + int LinkEncrypted; + + // + // Maximum number of bytes sent for each token. + // + + int TokenSize; + + // + // Maximum number of tokens that can be spent + // by the client proxy before having to block + // waiting for a reply. + // + + int TokenLimit; + + // + // Bitmask used to determine the distribution + // of channel ids between the client and server + // proxies. + // + + int ChannelMask; + + // + // Kill session if control parameters cannot + // be negotiated before this timeout. + // + + int InitTimeout; + + // + // Enter the congestion state if the remote does + // not reply to the ping within the given amount + // of time. + // + + int PingTimeout; + + // + // Enqueue motion notify events in server channel. + // + + int MotionTimeout; + + // + // Force an update of the congestion counter if + // the proxy is idle for this time. + // + + int IdleTimeout; + + // + // Close the connection if can't write before + // this timeout. + // + + int ChannelTimeout; + + // + // Close connection if can't write before + // this timeout. + // + + int ProxyTimeout; + + // + // How many milliseconds to wait for the shared + // memory completion event to become available. + // + + int ShmemTimeout; + + // + // Wait for applications to complete at the time + // proxy is shut down. + // + + int CleanupTimeout; + + // + // Wait this amount of milliseconds before any + // iteration of the house-keeping process. + // + + int KeeperTimeout; + + // + // Adjust timeout calculations. + // + + int LatencyTimeout; + + // + // Maximum allowed size of log files. + // + + int FileSizeLimit; + int FileSizeCheckTimeout; + + // + // What do we do at the end of session? If + // this flag is set we launch a new client + // letting the user run a new NX session. + // + + int EnableRestartOnShutdown; + + // + // The client can request the proxy to kill + // a number of processes before exiting. + // + + int *KillDaemonOnShutdown; + int KillDaemonOnShutdownNumber; + int KillDaemonOnShutdownLimit; + + // + // Do we generate a core dump and exit in + // case of program errors? + // + + int EnableCoreDumpOnAbort; + + // + // Is statistic output enabled? + // + + int EnableStatistics; + + // + // Version number of local and remote proxy. + // + + /* + * LocalVersionMaintenancePatch, RemoteVersionMaintenancePatch + * CompatVersionMaintenancePatch + * + * currently not used, for future compatibility checks + */ + int LocalVersionMajor; + int LocalVersionMinor; + int LocalVersionPatch; + int LocalVersionMaintenancePatch; + + int RemoteVersionMajor; + int RemoteVersionMinor; + int RemoteVersionPatch; + int RemoteVersionMaintenancePatch; + + int CompatVersionMajor; + int CompatVersionMinor; + int CompatVersionPatch; + int CompatVersionMaintenancePatch; + + // + // Compatibility version for the proxy + // + + static const char* const NXPROXY_COMPATIBILITY_VERSION; + + // + // Which unpack methods are implemented in proxy? + // + + unsigned char *LocalUnpackMethods; + unsigned char *RemoteUnpackMethods; + + // + // Memory restriction imposed by user. + // + + int LocalMemoryLevel; + + // + // Use or not differential compression + // and caching of X protocol messages. + // + + int LocalDeltaCompression; + int RemoteDeltaCompression; + + // + // Compression of images and replies. + // + + int LocalDataCompression; + int LocalDataCompressionLevel; + + int RemoteDataCompression; + int RemoteDataCompressionLevel; + + // + // Minimum packet size to be compressed. + // + + int LocalDataCompressionThreshold; + + // + // Compress or not data flowing through the proxy + // link. Level should be one of the ZLIB level as + // Z_DEFAULT_COMPRESSION or Z_BEST_COMPRESSION. + // + + int LocalStreamCompression; + int LocalStreamCompressionLevel; + + int RemoteStreamCompression; + int RemoteStreamCompressionLevel; + + // + // Size of read operations in read buffer classes. + // + + int ClientInitialReadSize; + int ClientMaximumBufferSize; + + int ServerInitialReadSize; + int ServerMaximumBufferSize; + + int ProxyInitialReadSize; + int ProxyMaximumBufferSize; + + int GenericInitialReadSize; + int GenericMaximumBufferSize; + + // + // Set initial size and resize policy of + // transport buffers. If maximum size is + // exceeded, print a warning. + // + + int TransportXBufferSize; + int TransportProxyBufferSize; + int TransportGenericBufferSize; + + int TransportXBufferThreshold; + int TransportProxyBufferThreshold; + int TransportGenericBufferThreshold; + + int TransportMaximumBufferSize; + + // + // Flush the data produced for the channel + // connection if it exceeds this size. + // + + int TransportFlushBufferSize; + + // + // Socket options. + // + + int OptionProxyKeepAlive; + int OptionProxyLowDelay; + int OptionProxyClientNoDelay; + int OptionProxyServerNoDelay; + int OptionClientNoDelay; + int OptionServerNoDelay; + + int OptionProxyReceiveBuffer; + int OptionClientReceiveBuffer; + int OptionServerReceiveBuffer; + + int OptionProxySendBuffer; + int OptionClientSendBuffer; + int OptionServerSendBuffer; + + int OptionProxyRetryAccept; + int OptionProxyRetryConnect; + int OptionServerRetryConnect; + + // + // Calculate current bitrate on proxy link + // using these observation periods. Value + // is in milliseconds. + // + + int ShortBitrateTimeFrame; + int LongBitrateTimeFrame; + + // + // Limit the bandwidth usage of the proxy + // link. + // + + int LocalBitrateLimit; + + int ClientBitrateLimit; + int ServerBitrateLimit; + + // + // This is the limit imposed by user on + // total cache size. + // + + int ClientTotalStorageSize; + int ServerTotalStorageSize; + + int LocalTotalStorageSize; + int RemoteTotalStorageSize; + + // + // Discard messages in store older than + // this amount of seconds. + // + + int StoreTimeLimit; + + // + // Any new message in store starts with + // this amount of hits. + // + + int StoreHitsAddBonus; + + // + // Unless it is loaded from persistent + // cache. + // + + int StoreHitsLoadBonus; + + // + // Stop increasing hits at this threshold. + // + + int StoreHitsLimit; + + // + // Give a special weight to messages put or + // taken from cache during startup time. + // + + int StoreHitsStartup; + + // + // Weight of touch and untoch operations. + // + + int StoreHitsTouch; + int StoreHitsUntouch; + + // + // Directives on size of messages to cache. + // + + int MinimumMessageSize; + int MaximumMessageSize; + + // + // Maximum size of a single X request. + // + + int MaximumRequestSize; + + // + // Currently selected streaming mode. + // + + int SplitMode; + + // + // Send new split data any given amount of + // milliseconds. + // + + int SplitTimeout; + + // + // Maximum number of distinct messages and + // maximum size in bytes of the temporary + // storage. + // + + int SplitTotalSize; + int SplitTotalStorageSize; + + // + // Don't split messages smaller that this + // threshold and send no more than the + // given amount of bytes in a single data + // shot when streaming the split messages. + // + + int SplitDataThreshold; + int SplitDataPacketLimit; + + // + // Agent related parameters. These values apply + // to the agent which, at startup, must query + // the user's settings. + // + + int PackMethod; + int PackQuality; + int HideRender; + int TaintReplies; + int TaintThreshold; + + // + // Do we allow shared memory image support in + // client and or server? + // + + int ShmemClient; + int ShmemServer; + + // + // Default size of shared memory segments used + // in MIT-SHM support. + // + + int ShmemClientSize; + int ShmemServerSize; + + // + // The user's home directory. + // + + char *HomePath; + + // + // The ".nx" directory, usually in + // the user's home. + // + + char *RootPath; + + // + // Usually the /usr/NX" directory. + // + + char *SystemPath; + + // + // Usually the "/tmp" directory. + // + + char *TempPath; + + // + // The complete path to the client. + // + + char *ClientPath; + + // + // String containing path of cache + // file selected for load or save. + // + + char *PersistentCachePath; + + // + // Name of selected cache file. + // + + char *PersistentCacheName; + + // + // Minimum size of cache in memory + // to proceed to its storage on disk. + // + + int PersistentCacheThreshold; + + // + // Is persistent cache enabled? + // + + int PersistentCacheEnableLoad; + int PersistentCacheEnableSave; + + // + // This is used just for test because + // it requires that client and server + // reside on the same machine. + // + + int PersistentCacheCheckOnShutdown; + + // + // Load packed image and render extension + // message stores. This currently depends + // on the type of session. + // + + int PersistentCacheLoadPacked; + int PersistentCacheLoadRender; + + // + // Maximum disk consumption of message + // caches on disk. + // + + int PersistentCacheDiskLimit; + + // + // String containing the base path + // of image cache files. + // + + char *ImageCachePath; + + // + // Is image cache enabled? + // + + int ImageCacheEnableLoad; + int ImageCacheEnableSave; + + // + // Maximum disk consumption of image + // caches on disk. + // + + int ImageCacheDiskLimit; + + // + // Only constructor, destructor + // and a few utility functions. + // + + Control(); + + ~Control(); + + // + // Should not leverage control to find channel + // stores' size limits. As most of values in + // control, this info must be moved elsewhere. + // + + int getUpperStorageSize() const + { + return (ClientTotalStorageSize > + ServerTotalStorageSize ? + ClientTotalStorageSize : + ServerTotalStorageSize); + } + + int getLowerStorageSize() const + { + return (ClientTotalStorageSize < + ServerTotalStorageSize ? + ClientTotalStorageSize : + ServerTotalStorageSize); + } + + void setProtoStep(int step); + + int getProtoStep(); + + private: + + // + // Look in Control.cpp. + // + + void setLocalUnpackMethods(); + + // + // Manage the encoding according + // to the protocol version. + // + + int protoStep_; + + // + // Min and max values allowed for protocol step + // depending on protocol version compatibility + // + + static const int NX_MIN_PROTO_STEP; + static const int NX_MAX_PROTO_STEP; + + // + // Check the validity of protocol step + // + + bool isValidProtoStep(int step) + { + return ((step >= NX_MIN_PROTO_STEP) && (step <= NX_MAX_PROTO_STEP)); + } + +}; + +#endif /* Control_H */ diff --git a/nxcomp/src/CopyArea.cpp b/nxcomp/src/CopyArea.cpp new file mode 100644 index 000000000..c2a19c2df --- /dev/null +++ b/nxcomp/src/CopyArea.cpp @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "CopyArea.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +int CopyAreaStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + CopyAreaMessage *copyArea = (CopyAreaMessage *) message; + + // + // Here is the fingerprint. + // + + copyArea -> src_drawable = GetULONG(buffer + 4, bigEndian); + copyArea -> dst_drawable = GetULONG(buffer + 8, bigEndian); + copyArea -> gcontext = GetULONG(buffer + 12, bigEndian); + + copyArea -> src_x = GetUINT(buffer + 16, bigEndian); + copyArea -> src_y = GetUINT(buffer + 18, bigEndian); + copyArea -> dst_x = GetUINT(buffer + 20, bigEndian); + copyArea -> dst_y = GetUINT(buffer + 22, bigEndian); + + copyArea -> width = GetUINT(buffer + 24, bigEndian); + copyArea -> height = GetUINT(buffer + 26, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int CopyAreaStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + CopyAreaMessage *copyArea = (CopyAreaMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(copyArea -> src_drawable, buffer + 4, bigEndian); + PutULONG(copyArea -> dst_drawable, buffer + 8, bigEndian); + PutULONG(copyArea -> gcontext, buffer + 12, bigEndian); + + PutUINT(copyArea -> src_x, buffer + 16, bigEndian); + PutUINT(copyArea -> src_y, buffer + 18, bigEndian); + PutUINT(copyArea -> dst_x, buffer + 20, bigEndian); + PutUINT(copyArea -> dst_y, buffer + 22, bigEndian); + + PutUINT(copyArea -> width, buffer + 24, bigEndian); + PutUINT(copyArea -> height, buffer + 26, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void CopyAreaStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + CopyAreaMessage *copyArea = (CopyAreaMessage *) message; + + *logofs << name() << ": Identity src_drawable " << copyArea -> src_drawable + << ", dst_drawable " << copyArea -> dst_drawable << ", gcontext " << copyArea -> gcontext + << ", src_x " << copyArea -> src_x << ", src_y " << copyArea -> src_y + << ", dst_x " << copyArea -> dst_x << ", dst_y " << copyArea -> dst_y + << ", width " << copyArea -> width << ", height " << copyArea -> height + << ", size " << copyArea -> size_ << ".\n"; + + #endif +} + +void CopyAreaStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 16, 12); +} + +void CopyAreaStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + CopyAreaMessage *copyArea = (CopyAreaMessage *) message; + CopyAreaMessage *cachedCopyArea = (CopyAreaMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << copyArea -> src_drawable + << " as " << "src_drawable" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(copyArea -> src_drawable, clientCache -> drawableCache); + + cachedCopyArea -> src_drawable = copyArea -> src_drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << copyArea -> dst_drawable + << " as " << "dst_drawable" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(copyArea -> dst_drawable, clientCache -> drawableCache); + + cachedCopyArea -> dst_drawable = copyArea -> dst_drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << copyArea -> gcontext + << " as " << "gcontext" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(copyArea -> gcontext, clientCache -> gcCache); + + cachedCopyArea -> gcontext = copyArea -> gcontext; +} + +void CopyAreaStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + CopyAreaMessage *copyArea = (CopyAreaMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + copyArea -> src_drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << copyArea -> src_drawable + << " as " << "src_drawable" << " field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + copyArea -> dst_drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << copyArea -> dst_drawable + << " as " << "dst_drawable" << " field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + copyArea -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << copyArea -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/CopyArea.h b/nxcomp/src/CopyArea.h new file mode 100644 index 000000000..6b2617875 --- /dev/null +++ b/nxcomp/src/CopyArea.h @@ -0,0 +1,192 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef CopyArea_H +#define CopyArea_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define COPYAREA_ENABLE_CACHE 1 +#define COPYAREA_ENABLE_DATA 0 +#define COPYAREA_ENABLE_SPLIT 0 +#define COPYAREA_ENABLE_COMPRESS 0 + +#define COPYAREA_DATA_LIMIT 0 +#define COPYAREA_DATA_OFFSET 28 + +#define COPYAREA_CACHE_SLOTS 3000 +#define COPYAREA_CACHE_THRESHOLD 5 +#define COPYAREA_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class CopyAreaMessage : public Message +{ + friend class CopyAreaStore; + + public: + + CopyAreaMessage() + { + } + + ~CopyAreaMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int src_drawable; + unsigned int dst_drawable; + unsigned int gcontext; + unsigned short src_x; + unsigned short src_y; + unsigned short dst_x; + unsigned short dst_y; + unsigned short width; + unsigned short height; +}; + +class CopyAreaStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + CopyAreaStore() : MessageStore() + { + enableCache = COPYAREA_ENABLE_CACHE; + enableData = COPYAREA_ENABLE_DATA; + enableSplit = COPYAREA_ENABLE_SPLIT; + enableCompress = COPYAREA_ENABLE_COMPRESS; + + dataLimit = COPYAREA_DATA_LIMIT; + dataOffset = COPYAREA_DATA_OFFSET; + + cacheSlots = COPYAREA_CACHE_SLOTS; + cacheThreshold = COPYAREA_CACHE_THRESHOLD; + cacheLowerThreshold = COPYAREA_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~CopyAreaStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "CopyArea"; + } + + virtual unsigned char opcode() const + { + return X_CopyArea; + } + + virtual unsigned int storage() const + { + return sizeof(CopyAreaMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new CopyAreaMessage(); + } + + virtual Message *create(const Message &message) const + { + return new CopyAreaMessage((const CopyAreaMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (CopyAreaMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* CopyArea_H */ diff --git a/nxcomp/src/CreateGC.cpp b/nxcomp/src/CreateGC.cpp new file mode 100644 index 000000000..34978de13 --- /dev/null +++ b/nxcomp/src/CreateGC.cpp @@ -0,0 +1,194 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "CreateGC.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int CreateGCStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + CreateGCMessage *createGC = (CreateGCMessage *) message; + + // + // Here is the fingerprint. + // + + createGC -> gcontext = GetULONG(buffer + 4, bigEndian); + createGC -> drawable = GetULONG(buffer + 8, bigEndian); + createGC -> value_mask = GetULONG(buffer + 12, bigEndian); + + // + // Clear the unused bytes carried in the + // payload to increase the effectiveness + // of the caching algorithm. + // + + if ((int) size > dataOffset) + { + #ifdef DEBUG + *logofs << name() << ": Removing unused bytes from the " + << "data payload.\n" << logofs_flush; + #endif + + createGC -> value_mask &= (1 << 23) - 1; + + unsigned int mask = 0x1; + unsigned char *source = (unsigned char *) buffer + CREATEGC_DATA_OFFSET; + unsigned long value = 0; + + for (unsigned int i = 0; i < 23; i++) + { + if (createGC -> value_mask & mask) + { + value = GetULONG(source, bigEndian); + + value &= (0xffffffff >> (32 - CREATEGC_FIELD_WIDTH[i])); + + PutULONG(value, source, bigEndian); + + source += 4; + } + + mask <<= 1; + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int CreateGCStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + CreateGCMessage *createGC = (CreateGCMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(createGC -> gcontext, buffer + 4, bigEndian); + PutULONG(createGC -> drawable, buffer + 8, bigEndian); + PutULONG(createGC -> value_mask, buffer + 12, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void CreateGCStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + CreateGCMessage *createGC = (CreateGCMessage *) message; + + *logofs << name() << ": Identity gcontext " << createGC -> gcontext << ", drawable " + << createGC -> drawable << ", value_mask " << createGC -> value_mask + << ", size " << createGC -> size_ << ".\n" << logofs_flush; + #endif +} + +void CreateGCStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // This didn't include the drawable + // in previous versions. + // + + md5_append(md5_state_, buffer + 8, 8); +} + +void CreateGCStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + CreateGCMessage *createGC = (CreateGCMessage *) message; + CreateGCMessage *cachedCreateGC = (CreateGCMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + // Since ProtoStep7 (#issue 108) + #ifdef TEST + *logofs << name() << ": Encoding value " << createGC -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeNewXidValue(createGC -> gcontext, clientCache -> lastId, + clientCache -> lastIdCache, clientCache -> gcCache, + clientCache -> freeGCCache); + + cachedCreateGC -> gcontext = createGC -> gcontext; +} + +void CreateGCStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + CreateGCMessage *createGC = (CreateGCMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeNewXidValue(value, clientCache -> lastId, + clientCache -> lastIdCache, clientCache -> gcCache, + clientCache -> freeGCCache); + + createGC -> gcontext = value; + + #ifdef TEST + *logofs << name() << ": Decoded value " << createGC -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/CreateGC.h b/nxcomp/src/CreateGC.h new file mode 100644 index 000000000..03e27d685 --- /dev/null +++ b/nxcomp/src/CreateGC.h @@ -0,0 +1,186 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef CreateGC_H +#define CreateGC_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define CREATEGC_ENABLE_CACHE 1 +#define CREATEGC_ENABLE_DATA 0 +#define CREATEGC_ENABLE_SPLIT 0 +#define CREATEGC_ENABLE_COMPRESS 0 + +#define CREATEGC_DATA_LIMIT 144 +#define CREATEGC_DATA_OFFSET 16 + +#define CREATEGC_CACHE_SLOTS 2000 +#define CREATEGC_CACHE_THRESHOLD 2 +#define CREATEGC_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class CreateGCMessage : public Message +{ + friend class CreateGCStore; + + public: + + CreateGCMessage() + { + } + + ~CreateGCMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int gcontext; + unsigned int drawable; + unsigned int value_mask; +}; + +class CreateGCStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + CreateGCStore() : MessageStore() + { + enableCache = CREATEGC_ENABLE_CACHE; + enableData = CREATEGC_ENABLE_DATA; + enableSplit = CREATEGC_ENABLE_SPLIT; + enableCompress = CREATEGC_ENABLE_COMPRESS; + + dataLimit = CREATEGC_DATA_LIMIT; + dataOffset = CREATEGC_DATA_OFFSET; + + cacheSlots = CREATEGC_CACHE_SLOTS; + cacheThreshold = CREATEGC_CACHE_THRESHOLD; + cacheLowerThreshold = CREATEGC_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~CreateGCStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "CreateGC"; + } + + virtual unsigned char opcode() const + { + return X_CreateGC; + } + + virtual unsigned int storage() const + { + return sizeof(CreateGCMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new CreateGCMessage(); + } + + virtual Message *create(const Message &message) const + { + return new CreateGCMessage((const CreateGCMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (CreateGCMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* CreateGC_H */ diff --git a/nxcomp/src/CreatePixmap.cpp b/nxcomp/src/CreatePixmap.cpp new file mode 100644 index 000000000..a60134cd5 --- /dev/null +++ b/nxcomp/src/CreatePixmap.cpp @@ -0,0 +1,280 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "CreatePixmap.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Constructors and destructors. +// + +CreatePixmapStore::CreatePixmapStore() + + : MessageStore() +{ + enableCache = CREATEPIXMAP_ENABLE_CACHE; + enableData = CREATEPIXMAP_ENABLE_DATA; + enableSplit = CREATEPIXMAP_ENABLE_SPLIT; + enableCompress = CREATEPIXMAP_ENABLE_COMPRESS; + + dataLimit = CREATEPIXMAP_DATA_LIMIT; + dataOffset = CREATEPIXMAP_DATA_OFFSET; + + cacheSlots = CREATEPIXMAP_CACHE_SLOTS; + cacheThreshold = CREATEPIXMAP_CACHE_THRESHOLD; + cacheLowerThreshold = CREATEPIXMAP_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +CreatePixmapStore::~CreatePixmapStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int CreatePixmapStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(*(buffer + 1), 8, + clientCache -> depthCache); + + encodeBuffer.encodeNewXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> drawableCache, + clientCache -> freeDrawableCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), + clientCache -> windowCache); + + encodeBuffer.encodeCachedValue(GetUINT(buffer + 12, bigEndian), 16, + clientCache -> createPixmapXCache, 8); + + encodeBuffer.encodeCachedValue(GetUINT(buffer + 14, bigEndian), 16, + clientCache -> createPixmapYCache, 8); + + #ifdef TEST + *logofs << name() << ": Encoded message. Size is " + << size << ".\n" << logofs_flush; + #endif + + return 1; +} + +int CreatePixmapStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned char cValue; + unsigned int value; + + size = 16; + + buffer = writeBuffer -> addMessage(size); + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + + *(buffer + 1) = cValue; + + decodeBuffer.decodeNewXidValue(value, + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> drawableCache, + clientCache -> freeDrawableCache); + + PutULONG(value, buffer + 4, bigEndian); + + decodeBuffer.decodeXidValue(value, + clientCache -> windowCache); + + PutULONG(value, buffer + 8, bigEndian); + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> createPixmapXCache, 8); + + PutUINT(value, buffer + 12, bigEndian); + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> createPixmapYCache, 8); + + PutUINT(value, buffer + 14, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Size is " + << size << ".\n" << logofs_flush; + #endif + + return 1; +} + +int CreatePixmapStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + CreatePixmapMessage *createPixmap = (CreatePixmapMessage *) message; + + createPixmap -> depth = *(buffer + 1); + + createPixmap -> id = GetULONG(buffer + 4, bigEndian); + createPixmap -> drawable = GetULONG(buffer + 8, bigEndian); + + createPixmap -> width = GetUINT(buffer + 12, bigEndian); + createPixmap -> height = GetUINT(buffer + 14, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Size is " + << createPixmap -> size_ << " identity is " + << createPixmap -> i_size_ << ".\n" + << logofs_flush; + #endif + + return 1; +} + +int CreatePixmapStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + CreatePixmapMessage *createPixmap = (CreatePixmapMessage *) message; + + *(buffer + 1) = createPixmap -> depth; + + PutULONG(createPixmap -> id, buffer + 4, bigEndian); + PutULONG(createPixmap -> drawable, buffer + 8, bigEndian); + + PutUINT(createPixmap -> width, buffer + 12, bigEndian); + PutUINT(createPixmap -> height, buffer + 14, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Size is " + << createPixmap -> size_ << " identity is " + << createPixmap -> i_size_ << ".\n" + << logofs_flush; + #endif + + return 1; +} + +void CreatePixmapStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + #ifdef WARNING + *logofs << name() << ": WARNING! Dump of identity not implemented.\n" + << logofs_flush; + #endif + + #endif +} + +void CreatePixmapStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 1, 1); + md5_append(md5_state_, buffer + 8, 8); +} + +void CreatePixmapStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + CreatePixmapMessage *createPixmap = (CreatePixmapMessage *) message; + CreatePixmapMessage *cachedCreatePixmap = (CreatePixmapMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeNewXidValue(createPixmap -> id, + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> drawableCache, + clientCache -> freeDrawableCache); + + cachedCreatePixmap -> id = createPixmap -> id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Size is " + << createPixmap -> size_ << " identity is " + << createPixmap -> i_size_ << ".\n" + << logofs_flush; + #endif +} + +void CreatePixmapStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + CreatePixmapMessage *createPixmap = (CreatePixmapMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeNewXidValue(createPixmap -> id, + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> drawableCache, + clientCache -> freeDrawableCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Size is " + << createPixmap -> size_ << " identity is " + << createPixmap -> i_size_ << ".\n" + << logofs_flush; + #endif +} diff --git a/nxcomp/src/CreatePixmap.h b/nxcomp/src/CreatePixmap.h new file mode 100644 index 000000000..0a3212dd9 --- /dev/null +++ b/nxcomp/src/CreatePixmap.h @@ -0,0 +1,162 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef CreatePixmap_H +#define CreatePixmap_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define CREATEPIXMAP_ENABLE_CACHE 1 +#define CREATEPIXMAP_ENABLE_DATA 0 +#define CREATEPIXMAP_ENABLE_SPLIT 0 +#define CREATEPIXMAP_ENABLE_COMPRESS 0 + +#define CREATEPIXMAP_DATA_LIMIT 16 +#define CREATEPIXMAP_DATA_OFFSET 16 + +#define CREATEPIXMAP_CACHE_SLOTS 1000 +#define CREATEPIXMAP_CACHE_THRESHOLD 2 +#define CREATEPIXMAP_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class CreatePixmapMessage : public Message +{ + friend class CreatePixmapStore; + + public: + + CreatePixmapMessage() + { + } + + ~CreatePixmapMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char depth; + + unsigned int id; + unsigned int drawable; + + unsigned short width; + unsigned short height; +}; + +class CreatePixmapStore : public MessageStore +{ + public: + + CreatePixmapStore(); + + virtual ~CreatePixmapStore(); + + virtual const char *name() const + { + return "CreatePixmap"; + } + + virtual unsigned char opcode() const + { + return X_CreatePixmap; + } + + virtual unsigned int storage() const + { + return sizeof(CreatePixmapMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new CreatePixmapMessage(); + } + + virtual Message *create(const Message &message) const + { + return new CreatePixmapMessage((const CreatePixmapMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (CreatePixmapMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* CreatePixmap_H */ diff --git a/nxcomp/src/DecodeBuffer.cpp b/nxcomp/src/DecodeBuffer.cpp new file mode 100644 index 000000000..4c1530d9b --- /dev/null +++ b/nxcomp/src/DecodeBuffer.cpp @@ -0,0 +1,639 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "Control.h" + +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +DecodeBuffer::DecodeBuffer(const unsigned char *data, unsigned int length) + + : buffer_(data), end_(buffer_ + length), nextSrc_(buffer_), srcMask_(0x80) +{ + // Since ProtoStep7 (#issue 108) + end_ = buffer_ + length - DECODE_BUFFER_POSTFIX_SIZE; +} + +int DecodeBuffer::decodeValue(unsigned int &value, unsigned int numBits, + unsigned int blockSize, int endOkay) +{ + #ifdef DUMP + *logofs << "DecodeBuffer: Decoding " << numBits + << " bits value with block " << blockSize + << " and " << (nextSrc_ - buffer_) + << " bytes in buffer.\n" << logofs_flush; + #endif + + unsigned int result = 0; + unsigned int destMask = 0x1; + unsigned int bitsRead = 0; + + if (blockSize == 0) + blockSize = numBits; + + unsigned char nextSrcChar = *nextSrc_; + unsigned int numBlocks = 1; + + do + { + if (numBlocks == 4) + { + blockSize = numBits; + } + + unsigned int bitsToRead = (blockSize > numBits - bitsRead ? + numBits - bitsRead : blockSize); + unsigned int count = 0; + unsigned char lastBit; + + do + { + if (nextSrc_ >= end_) + { + if (!endOkay) + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [A] " + << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) + << " end_ = " << (end_ - buffer_) << ".\n" + << logofs_flush; + #endif + + // + // Label "context" is just used to identify + // the routine which detected the problem in + // present source file. + // + + cerr << "Error" << ": Failure decoding data in context [A].\n"; + + HandleAbort(); + } + + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [B] " + << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) + << " end_ = " << (end_ - buffer_) << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [B].\n"; + + HandleAbort(); + } + + lastBit = (nextSrcChar & srcMask_); + + if (lastBit) + result |= destMask; + + srcMask_ >>= 1; + + if (srcMask_ == 0) + { + srcMask_ = 0x80; + nextSrc_++; + nextSrcChar = *nextSrc_; + } + + destMask <<= 1; + } + while (bitsToRead > ++count); + + bitsRead += bitsToRead; + + if (bitsRead < numBits) + { + if (nextSrc_ >= end_) + { + if (!endOkay) + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [C] " + << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) + << " end_ = " << (end_ - buffer_) << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [C].\n"; + + HandleAbort(); + } + + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [D] " + << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) + << " end_ = " << (end_ - buffer_) << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [D].\n"; + + HandleAbort(); + } + + unsigned char moreData = (nextSrcChar & srcMask_); + + srcMask_ >>= 1; + + if (srcMask_ == 0) + { + srcMask_ = 0x80; + nextSrc_++; + nextSrcChar = *nextSrc_; + } + + if (!moreData) + { + if (lastBit) + { + do + { + result |= destMask; + destMask <<= 1; + } + while (numBits > ++bitsRead); + } + else + bitsRead = numBits; + } + } + + blockSize >>= 1; + + if (blockSize < 2) + blockSize = 2; + + numBlocks++; + } + while (numBits > bitsRead); + + value = result; + + return 1; +} + +int DecodeBuffer::decodeCachedValue(unsigned int &value, unsigned int numBits, + IntCache &cache, unsigned int blockSize, + int endOkay) +{ + #ifdef DUMP + *logofs << "DecodeBuffer: Decoding " << numBits + << " bits cached value with block " << blockSize + << " and " << (nextSrc_ - buffer_) + << " bytes in buffer.\n" << logofs_flush; + #endif + + if (nextSrc_ >= end_) + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [E] " + << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) + << " end_ = " << (end_ - buffer_) << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [E].\n"; + + HandleAbort(); + } + + unsigned int index = 0; + unsigned char nextSrcChar = *nextSrc_; + + while (!(nextSrcChar & srcMask_)) + { + index++; + srcMask_ >>= 1; + if (srcMask_ == 0) + { + srcMask_ = 0x80; + nextSrc_++; + if (nextSrc_ >= end_) + { + if (!endOkay) + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [F] " + << "in decodeCachedValue() nextSrc_ = " + << (nextSrc_ - buffer_) << " end_ = " + << (end_ - buffer_) << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [F].\n"; + + HandleAbort(); + } + + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [G] " + << "in decodeValue() nextSrc_ = " << (nextSrc_ - buffer_) + << " end_ = " << (end_ - buffer_) << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [G].\n"; + + HandleAbort(); + } + + nextSrcChar = *nextSrc_; + } + } + + srcMask_ >>= 1; + + if (srcMask_ == 0) + { + srcMask_ = 0x80; + nextSrc_++; + } + + if (index == 2) + { + // Since ProtoStep8 (#issue 108) + blockSize = cache.getBlockSize(blockSize); + + if (decodeValue(value, numBits, blockSize, endOkay)) + { + cache.insert(value, IntMask[numBits]); + + return 1; + } + + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [H] " + << "in decodeCacheValue() with no value found.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [H].\n"; + + HandleAbort(); + } + else + { + if (index > 2) + { + index--; + } + + if (index > cache.getSize()) + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [I] " + << "in decodeCachedValue() index = " << index + << " cache size = " << cache.getSize() << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [I].\n"; + + HandleAbort(); + } + + value = cache.get(index); + + return 1; + } +} + +int DecodeBuffer::decodeCachedValue(unsigned char &value, unsigned int numBits, + CharCache &cache, unsigned int blockSize, + int endOkay) +{ + #ifdef DUMP + *logofs << "DecodeBuffer: Decoding " << numBits + << " bits char cached value with block " << blockSize + << " and " << nextSrc_ - buffer_ << " bytes read out of " + << end_ - buffer_ << ".\n" << logofs_flush; + #endif + + if (nextSrc_ >= end_) + { + #ifdef TEST + *logofs << "DecodeBuffer: End of buffer reached in context [J] with " + << nextSrc_ - buffer_ << " bytes read out of " + << end_ - buffer_ << ".\n" << logofs_flush; + #endif + + return 0; + } + + unsigned int index = 0; + unsigned char nextSrcChar = *nextSrc_; + + while (!(nextSrcChar & srcMask_)) + { + index++; + srcMask_ >>= 1; + + if (srcMask_ == 0) + { + srcMask_ = 0x80; + nextSrc_++; + + if (nextSrc_ >= end_) + { + if (!endOkay) + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [K] " + << "in decodeCachedValue() nextSrc_ " + << (nextSrc_ - buffer_) << " end_ " << (end_ - buffer_) + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [K].\n"; + + HandleAbort(); + } + + #ifdef TEST + *logofs << "DecodeBuffer: End of buffer reached in context [L] with " + << nextSrc_ - buffer_ << " bytes read out of " + << end_ - buffer_ << ".\n" << logofs_flush; + #endif + + return 0; + } + + nextSrcChar = *nextSrc_; + } + } + + srcMask_ >>= 1; + + if (srcMask_ == 0) + { + srcMask_ = 0x80; + nextSrc_++; + } + + if (index == 2) + { + unsigned int temp; + + if (decodeValue(temp, numBits, blockSize, endOkay)) + { + value = (unsigned char) temp; + + cache.insert(value); + } + else + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [M] " + << "in decodeValue() with index = 2.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [M].\n"; + + HandleAbort(); + } + } + else + { + if (index > 2) + { + index--; + } + + if (index > cache.getSize()) + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [N] " + << "in decodeCachedValue() " << "index = " << index + << " cache size = " << cache.getSize() << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [N].\n"; + + HandleAbort(); + } + + value = cache.get(index); + } + + return 1; +} + +// +// Simply returns a pointer to the correct spot in +// the internal buffer. If the caller needs this +// data to last beyond the lifetime of the internal +// buffer, it must copy the data in its own memory. +// + +const unsigned char *DecodeBuffer::decodeMemory(unsigned int numBytes) +{ + #ifdef DUMP + *logofs << "DecodeBuffer: Decoding " << numBytes + << " bytes of memory with " << (nextSrc_ - buffer_) + << " bytes in buffer.\n" << logofs_flush; + #endif + + const unsigned char *result; + + // + // Force ourselves to a byte boundary. + // Is up to application to ensure data + // is word alligned when needed. + // + + if (srcMask_ != 0x80) + { + srcMask_ = 0x80; + nextSrc_++; + } + + result = nextSrc_; + + if (numBytes > DECODE_BUFFER_OVERFLOW_SIZE) + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Can't decode a buffer of " + << numBytes << " bytes with limit set to " + << DECODE_BUFFER_OVERFLOW_SIZE << ".\n" + << logofs_flush; + + *logofs << "DecodeBuffer: PANIC! Assuming failure decoding " + << "data in context [O].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Should never decode buffer of size " + << "greater than " << DECODE_BUFFER_OVERFLOW_SIZE + << " bytes.\n"; + + cerr << "Error" << ": Assuming failure decoding data in " + << "context [O].\n"; + + HandleAbort(); + } + else if (end_ - nextSrc_ < (int) numBytes) + { + #ifdef PANIC + *logofs << "DecodeBuffer: PANIC! Assertion failed. Error [P] " + << "in decodeMemory() " << "with length " << numBytes + << " and " << (end_ - nextSrc_) + << " bytes remaining.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failure decoding data in context [P].\n"; + + HandleAbort(); + } + + nextSrc_ += numBytes; + + return result; +} + +void DecodeBuffer::decodeActionValue(unsigned char &value, unsigned short &position, + ActionCache &cache) +{ + unsigned int t; + + decodeCachedValue(t, 15, *(cache.base_[cache.slot_])); + + cache.last_ += t; + cache.last_ &= 0x7fff; + + value = cache.last_ >> 13; + + position = cache.last_ & 0x1fff; + + #ifdef DEBUG + *logofs << "DecodeBuffer: Decoded value " + << (unsigned) value << " and position " + << position << " with base " << cache.slot_ + << ".\n" << logofs_flush; + #endif + + #ifdef DEBUG + *logofs << "DecodeBuffer: Action block prediction is " + << (*(cache.base_[cache.slot_])).getBlockSize(15) + << ".\n" << logofs_flush; + #endif + + cache.slot_ = (cache.last_ & 0xff); +} + +void DecodeBuffer::decodeNewXidValue(unsigned int &value, unsigned int &lastId, + IntCache &lastIdCache, IntCache &cache, + FreeCache &freeCache) +{ + decodeCachedValue(value, 29, lastIdCache); + + lastId += (value + 1); + lastId &= 0x1fffffff; + + value = lastId; + + cache.push(value, 0x1fffffff); + + freeCache.push(value, 0x1fffffff); +} + +void DecodeBuffer::decodeNewXidValue(unsigned int &value, unsigned int &lastId, + IntCache &lastIdCache, XidCache &cache, + FreeCache &freeCache) +{ + decodeCachedValue(value, 29, lastIdCache); + + #ifdef DEBUG + *logofs << "DecodeBuffer: Decoded new Xid difference " + << value << ".\n" << logofs_flush; + #endif + + lastId += (value + 1); + lastId &= 0x1fffffff; + + value = lastId; + + unsigned int t = (value - cache.last_); + + cache.last_ = value; + + #ifdef DEBUG + *logofs << "DecodeBuffer: Decoded new Xid " << value + << " with base " << cache.slot_ << ".\n" + << logofs_flush; + #endif + + cache.slot_ = (value & 0xff); + + cache.base_[cache.slot_] -> push(t, 0x1fffffff); + + freeCache.push(value, 0x1fffffff); +} + +void DecodeBuffer::decodeXidValue(unsigned int &value, XidCache &cache) +{ + unsigned int t; + + decodeCachedValue(t, 29, *(cache.base_[cache.slot_])); + + cache.last_ += t; + cache.last_ &= 0x1fffffff; + + value = cache.last_; + + #ifdef DEBUG + *logofs << "DecodeBuffer: Decoded Xid " << value + << " with base " << cache.slot_ << ".\n" + << logofs_flush; + #endif + + cache.slot_ = (value & 0xff); + + #ifdef DEBUG + *logofs << "DecodeBuffer: Xid block prediction is " + << (*(cache.base_[cache.slot_])).getBlockSize(29) + << ".\n" << logofs_flush; + #endif +} + +void DecodeBuffer::decodeFreeXidValue(unsigned int &value, FreeCache &cache) +{ + decodeCachedValue(value, 29, cache); +} + diff --git a/nxcomp/src/DecodeBuffer.h b/nxcomp/src/DecodeBuffer.h new file mode 100644 index 000000000..f5f84c54f --- /dev/null +++ b/nxcomp/src/DecodeBuffer.h @@ -0,0 +1,138 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef DecodeBuffer_H +#define DecodeBuffer_H + +#include + +#include "IntCache.h" +#include "CharCache.h" +#include "XidCache.h" +#include "FreeCache.h" +#include "OpcodeCache.h" +#include "ActionCache.h" + +#define DECODE_BUFFER_OVERFLOW_SIZE 4194304 + +#define DECODE_BUFFER_POSTFIX_SIZE 1 + +class DecodeBuffer +{ + public: + + DecodeBuffer(const unsigned char *data, unsigned int length); + + ~DecodeBuffer() + { + } + + int decodeValue(unsigned int &value, unsigned int numBits, + unsigned int blockSize = 0, int endOkay = 0); + + int decodeCachedValue(unsigned int &value, unsigned int numBits, + IntCache &cache, unsigned int blockSize = 0, + int endOkay = 0); + + int decodeCachedValue(unsigned char &value, unsigned int numBits, + CharCache &cache, unsigned int blockSize = 0, + int endOkay = 0); + + void decodeDiffCachedValue(unsigned int &value, unsigned int &previous, + unsigned int numBits, IntCache &cache, + unsigned int blockSize = 0) + { + decodeCachedValue(value, numBits, cache, blockSize); + + previous += (value + 1); + previous &= (0xffffffff >> (32 - numBits)); + + value = previous; + } + + void decodeBoolValue(unsigned int &value) + { + decodeValue(value, 1); + } + + int decodeOpcodeValue(unsigned char &value, OpcodeCache &cache, int endOkay = 0) + { + int result = decodeCachedValue(value, 8, cache.base_[cache.slot_], 8, endOkay); + + if (result == 1) + { + cache.slot_ = value; + } + + return result; + } + + void decodeActionValue(unsigned char &value, unsigned short &position, + ActionCache &cache); + + void decodeNewXidValue(unsigned int &value, unsigned int &lastId, + IntCache &lastIdCache, IntCache &cache, + FreeCache &freeCache); + + void decodeNewXidValue(unsigned int &value, unsigned int &lastId, + IntCache &lastIdCache, XidCache &cache, + FreeCache &freeCache); + + void decodeXidValue(unsigned int &value, XidCache &cache); + + void decodeFreeXidValue(unsigned int &value, FreeCache &cache); + + void decodeTextData(unsigned char *buffer, unsigned int numBytes) + { + decodeMemory(buffer, numBytes); + } + + void decodeIntData(unsigned char *buffer, unsigned int numBytes) + { + decodeMemory(buffer, numBytes); + } + + void decodeLongData(unsigned char *buffer, unsigned int numBytes) + { + decodeMemory(buffer, numBytes); + } + + const unsigned char *decodeMemory(unsigned int numBytes); + + void decodeMemory(unsigned char *buffer, unsigned int numBytes) + { + memcpy(buffer, decodeMemory(numBytes), numBytes); + } + + private: + + const unsigned char *buffer_; + const unsigned char *end_; + const unsigned char *nextSrc_; + + unsigned char srcMask_; +}; + +#endif /* DecodeBuffer_H */ diff --git a/nxcomp/src/EncodeBuffer.cpp b/nxcomp/src/EncodeBuffer.cpp new file mode 100644 index 000000000..e112113a8 --- /dev/null +++ b/nxcomp/src/EncodeBuffer.cpp @@ -0,0 +1,623 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "Control.h" + +#include "EncodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +#define ADVANCE_DEST \ +\ +if (destShift_ == 0) \ +{ \ + destShift_ = 7; nextDest_++; *nextDest_ = 0; \ +} \ +else \ +{ \ + destShift_--; \ +} + +EncodeBuffer::EncodeBuffer() +{ + size_ = ENCODE_BUFFER_DEFAULT_SIZE; + + buffer_ = new unsigned char[size_ + ENCODE_BUFFER_PREFIX_SIZE + + ENCODE_BUFFER_POSTFIX_SIZE] + ENCODE_BUFFER_PREFIX_SIZE; + end_ = buffer_ + size_; + + nextDest_ = buffer_; + *nextDest_ = 0; + destShift_ = 7; + + lastBits_ = 0; + + initialSize_ = ENCODE_BUFFER_DEFAULT_SIZE; + thresholdSize_ = ENCODE_BUFFER_DEFAULT_SIZE << 1; + maximumSize_ = ENCODE_BUFFER_DEFAULT_SIZE << 4; +} + +EncodeBuffer::~EncodeBuffer() +{ + delete [] (buffer_ - ENCODE_BUFFER_PREFIX_SIZE); +} + +void EncodeBuffer::setSize(unsigned int initialSize, unsigned int thresholdSize, + unsigned int maximumSize) +{ + initialSize_ = initialSize; + thresholdSize_ = thresholdSize; + maximumSize_ = maximumSize; + + #ifdef TEST + *logofs << "EncodeBuffer: Set buffer sizes to " + << initialSize_ << "/" << thresholdSize_ + << "/" << maximumSize_ << ".\n" + << logofs_flush; + #endif +} + +void EncodeBuffer::fullReset() +{ + if (size_ > initialSize_) + { + delete [] (buffer_ - ENCODE_BUFFER_PREFIX_SIZE); + + size_ = initialSize_; + + buffer_ = new unsigned char[size_ + ENCODE_BUFFER_PREFIX_SIZE + + ENCODE_BUFFER_POSTFIX_SIZE] + ENCODE_BUFFER_PREFIX_SIZE; + } + + end_ = buffer_ + size_; + + nextDest_ = buffer_; + *nextDest_ = 0; + destShift_ = 7; + + lastBits_ = 0; +} + +void EncodeBuffer::encodeValue(unsigned int value, unsigned int numBits, + unsigned int blockSize) +{ + #ifdef DUMP + *logofs << "EncodeBuffer: Encoding " << numBits + << " bits value with block " << blockSize + << " and " << (nextDest_ - buffer_) + << " bytes in buffer.\n" << logofs_flush; + #endif + + value &= IntMask[numBits]; + + unsigned int srcMask = 0x1; + unsigned int bitsWritten = 0; + + if (blockSize == 0) + blockSize = numBits; + + if (end_ - nextDest_ < 8) + { + growBuffer(); + } + + unsigned int numBlocks = 1; + + do + { + if (numBlocks == 4) + blockSize = numBits; + + unsigned int bitsToWrite = (blockSize > numBits - bitsWritten ? + numBits - bitsWritten : blockSize); + unsigned int count = 0; + unsigned int lastBit; + + do + { + lastBit = (value & srcMask); + if (lastBit) + *nextDest_ |= (1 << destShift_); + ADVANCE_DEST; + srcMask <<= 1; + } + while (bitsToWrite > ++count); + + bitsWritten += bitsToWrite; + + if (bitsWritten < numBits) + { + unsigned int tmpMask = srcMask; + unsigned int i = bitsWritten; + + if (lastBit) + { + do + { + unsigned int nextBit = (value & tmpMask); + + if (!nextBit) + break; + + tmpMask <<= 1; + } + while (numBits > ++i); + } + else + { + do + { + unsigned int nextBit = (value & tmpMask); + + if (nextBit) + break; + + tmpMask <<= 1; + } + while (numBits > ++i); + } + + if (i < numBits) + *nextDest_ |= (1 << destShift_); + else + bitsWritten = numBits; + + ADVANCE_DEST; + } + blockSize >>= 1; + + if (blockSize < 2) + blockSize = 2; + + numBlocks++; + } + while (numBits > bitsWritten); +} + +void EncodeBuffer::encodeCachedValue(unsigned int value, unsigned int numBits, + IntCache &cache, unsigned int blockSize) +{ + #ifdef DUMP + *logofs << "EncodeBuffer: Encoding " << numBits + << " bits cached value with block " << blockSize + << " and " << (nextDest_ - buffer_) + << " bytes in buffer.\n" << logofs_flush; + #endif + + value &= IntMask[numBits]; + + if (end_ - nextDest_ < 8) + { + growBuffer(); + } + + blockSize = cache.getBlockSize(blockSize); + + unsigned int index; + unsigned int sameDiff; + + #ifdef DUMP + + diffBits(); + + #endif + + if (cache.lookup(value, index, IntMask[numBits], sameDiff)) + { + if (index > 1) + index++; + + while (destShift_ < index) + { + index -= destShift_; + index--; + destShift_ = 7; + nextDest_++; + *nextDest_ = 0; + } + + destShift_ -= index; + *nextDest_ |= (1 << destShift_); + ADVANCE_DEST; + + #ifdef DUMP + *logofs << "EncodeBuffer: Encoded cached int using " + << diffBits() << " bits out of " << numBits + << ".\n" << logofs_flush; + #endif + } + else + { + ADVANCE_DEST; + ADVANCE_DEST; + *nextDest_ |= (1 << destShift_); + ADVANCE_DEST; + + // + // The attempt is very seldom successful. + // Avoid to encode the additional bool. + // + + // Since ProtoStep8 (#issue 108) + #ifdef DUMP + *logofs << "EncodeBuffer: Encoded missed int using " + << diffBits() << " bits out of " << numBits + << ".\n" << logofs_flush; + #endif + + encodeValue(value, numBits, blockSize); + } +} + +void EncodeBuffer::encodeCachedValue(unsigned char value, unsigned int numBits, + CharCache &cache, unsigned int blockSize) +{ + #ifdef DUMP + *logofs << "EncodeBuffer: Encoding " << numBits + << " bits char cached value with block " << blockSize + << " and " << (nextDest_ - buffer_) + << " bytes in buffer.\n" << logofs_flush; + #endif + + value &= IntMask[numBits]; + + if (end_ - nextDest_ < 8) + { + growBuffer(); + } + + unsigned int index; + + #ifdef DUMP + + diffBits(); + + #endif + + if (cache.lookup(value, index)) + { + if (index > 1) + index++; + + while (destShift_ < index) + { + index -= destShift_; + index--; + destShift_ = 7; + nextDest_++; + *nextDest_ = 0; + } + + destShift_ -= index; + *nextDest_ |= (1 << destShift_); + ADVANCE_DEST; + + #ifdef DUMP + *logofs << "EncodeBuffer: Encoded cached char using " + << diffBits() << " bits out of " << numBits + << ".\n" << logofs_flush; + #endif + } + else + { + ADVANCE_DEST; + ADVANCE_DEST; + *nextDest_ |= (1 << destShift_); + ADVANCE_DEST; + + encodeValue(value, numBits, blockSize); + + #ifdef DUMP + *logofs << "EncodeBuffer: Encoded missed char using " + << diffBits() << " bits out of " << numBits + << ".\n" << logofs_flush; + #endif + } +} + +void EncodeBuffer::encodeMemory(const unsigned char *buffer, unsigned int numBytes) +{ + #ifdef DUMP + *logofs << "EncodeBuffer: Encoding " << numBytes + << " bytes of memory with " << (nextDest_ - buffer_) + << " bytes in buffer.\n" << logofs_flush; + #endif + + if (numBytes > ENCODE_BUFFER_OVERFLOW_SIZE) + { + #ifdef PANIC + *logofs << "EncodeBuffer: PANIC! Should never encode buffer " + << "of size greater than " << ENCODE_BUFFER_OVERFLOW_SIZE + << " bytes.\n" << logofs_flush; + + *logofs << "EncodeBuffer: PANIC! Assuming failure encoding data " + << "in context [A].\n" << logofs_flush; + #endif + + // + // Label "context" is just used to identify + // the routine which detected the problem in + // present source file. + // + + cerr << "Error" << ": Should never encode buffer of size " + << "greater than " << ENCODE_BUFFER_OVERFLOW_SIZE + << " bytes.\n"; + + cerr << "Error" << ": Assuming failure encoding data " + << "in context [A].\n" ; + + HandleAbort(); + } + + alignBuffer(); + + if (end_ - nextDest_ < (int) numBytes) + { + growBuffer(numBytes); + } + + memcpy(nextDest_, buffer, numBytes); + + nextDest_ += numBytes; + + if (nextDest_ == end_) + { + growBuffer(); + } + else if (nextDest_ > end_) + { + #ifdef PANIC + *logofs << "EncodeBuffer: PANIC! Assertion failed. Error [B] " + << "in encodeMemory() nextDest_ " << (nextDest_ - buffer) + << " end_ " << (end_ - buffer) << ".\n" + << logofs_flush; + #endif + + // + // Label "context" is just used to identify + // the routine which detected the problem in + // present source file. + // + + cerr << "Error" << ": Failure encoding raw data " + << "in context [B].\n" ; + + HandleAbort(); + } + + *nextDest_ = 0; +} + +unsigned int EncodeBuffer::getLength() const +{ + unsigned int length = nextDest_ - buffer_; + + if (destShift_ != 7) + { + length++; + } + + // Since ProtoStep7 (#issue 108) + if (length > 0) + { + return length + ENCODE_BUFFER_POSTFIX_SIZE; + } + + return length; +} + +unsigned int EncodeBuffer::diffBits() +{ + unsigned int bits = ((nextDest_ - buffer_) << 3); + + bits += (7 - destShift_); + + unsigned int diff = bits - lastBits_; + + lastBits_ = bits; + + return diff; +} + +void EncodeBuffer::growBuffer(unsigned int numBytes) +{ + if (numBytes == 0) + { + numBytes = initialSize_; + } + + unsigned int bytesInBuffer = nextDest_ - buffer_; + + unsigned int newSize = thresholdSize_; + + while (newSize < bytesInBuffer + numBytes) + { + newSize <<= 1; + + if (newSize > maximumSize_) + { + newSize = bytesInBuffer + numBytes + initialSize_; + } + } + + unsigned char *newBuffer; + + newBuffer = new unsigned char[newSize + ENCODE_BUFFER_PREFIX_SIZE + + ENCODE_BUFFER_POSTFIX_SIZE] + ENCODE_BUFFER_PREFIX_SIZE; + + if (newBuffer == NULL) + { + #ifdef PANIC + *logofs << "EncodeBuffer: PANIC! Error in context [C] " + << "growing buffer to accommodate " << numBytes + << " bytes .\n" << logofs_flush; + #endif + + cerr << "Error" << ": Error in context [C] " + << "growing encode buffer to accommodate " + << numBytes << " bytes.\n"; + + HandleAbort(); + } + + #ifdef TEST + if (newSize >= maximumSize_) + { + *logofs << "EncodeBuffer: WARNING! Buffer grown to reach " + << "size of " << newSize << " bytes.\n" + << logofs_flush; + } + #endif + + // + // Prefix should not contain any valid data. + // It is proxy that will fill it with control + // messages and data length at the time a new + // frame is written to socket. + // + + memcpy(newBuffer, buffer_, bytesInBuffer + 1); + + newBuffer[bytesInBuffer + 1] = 0; + + delete [] (buffer_ - ENCODE_BUFFER_PREFIX_SIZE); + + buffer_ = newBuffer; + size_ = newSize; + end_ = buffer_ + size_; + + nextDest_ = buffer_ + bytesInBuffer; +} + +void EncodeBuffer::alignBuffer() +{ + if (destShift_ != 7) + { + destShift_ = 7; + nextDest_++; + + if (nextDest_ >= end_) + { + growBuffer(); + } + + *nextDest_ = 0; + } +} + +void EncodeBuffer::encodeActionValue(unsigned char value, unsigned short position, + ActionCache &cache) +{ + unsigned int v = (value << 13) | position; + + unsigned int t = (v - cache.last_); + + encodeCachedValue(t, 15, *(cache.base_[cache.slot_])); + + cache.last_ = v; + + #ifdef DEBUG + *logofs << "EncodeBuffer: Encoded value " + << (unsigned) value << " and position " + << position << " with base " << cache.slot_ + << ".\n" << logofs_flush; + #endif + + cache.slot_ = (cache.last_ & 0xff); +} + +void EncodeBuffer::encodeNewXidValue(unsigned int value, unsigned int &lastId, + IntCache &lastIdCache, IntCache &cache, + FreeCache &freeCache) +{ + encodeCachedValue((value - 1) - lastId, 29, lastIdCache); + + lastId = value; + + cache.push(value, 0x1fffffff); + + freeCache.push(value, 0x1fffffff); +} + +void EncodeBuffer::encodeNewXidValue(unsigned int value, unsigned int &lastId, + IntCache &lastIdCache, XidCache &cache, + FreeCache &freeCache) +{ + encodeCachedValue((value - 1) - lastId, 29, lastIdCache); + + lastId = value; + + unsigned int t = (value - cache.last_); + + cache.last_ = value; + + #ifdef DEBUG + *logofs << "EncodeBuffer: Encoded new Xid " << value + << " with base " << cache.slot_ << ".\n" + << logofs_flush; + #endif + + cache.slot_ = (value & 0xff); + + cache.base_[cache.slot_] -> push(t, 0x1fffffff); + + freeCache.push(value, IntMask[29]); +} + +void EncodeBuffer::encodeXidValue(unsigned int value, XidCache &cache) +{ + unsigned int t = (value - cache.last_); + + encodeCachedValue(t, 29, *(cache.base_[cache.slot_])); + + cache.last_ = value; + + #ifdef DEBUG + *logofs << "EncodeBuffer: Encoded Xid " << value + << " with base " << cache.slot_ << ".\n" + << logofs_flush; + #endif + + cache.slot_ = (value & 0xff); +} + +void EncodeBuffer::encodeFreeXidValue(unsigned int value, FreeCache &cache) +{ + encodeCachedValue(value, 29, cache); +} diff --git a/nxcomp/src/EncodeBuffer.h b/nxcomp/src/EncodeBuffer.h new file mode 100644 index 000000000..67f6ff093 --- /dev/null +++ b/nxcomp/src/EncodeBuffer.h @@ -0,0 +1,183 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef EncodeBuffer_H +#define EncodeBuffer_H + +#include "IntCache.h" +#include "CharCache.h" +#include "XidCache.h" +#include "FreeCache.h" +#include "OpcodeCache.h" +#include "ActionCache.h" + +#define ENCODE_BUFFER_DEFAULT_SIZE 16384 + +// +// This should match the maximum size of +// a single message added to write buffer +// (see WriteBuffer.h). +// + +#define ENCODE_BUFFER_OVERFLOW_SIZE 4194304 + +// +// Adjust for the control messages and the +// frame length added by the proxy. +// + +#define ENCODE_BUFFER_PREFIX_SIZE 64 + +// +// The encode routines may write one byte +// past the nominal end of the encode buffer. +// This additional byte is included in the +// payload. This is actually a harmless bug. +// + +#define ENCODE_BUFFER_POSTFIX_SIZE 1 + +class EncodeBuffer +{ + public: + + EncodeBuffer(); + + ~EncodeBuffer(); + + void setSize(unsigned int initialSize, unsigned int thresholdSize, + unsigned int maximumSize); + + void encodeValue(unsigned int value, unsigned int numBits, + unsigned int blockSize = 0); + + void encodeCachedValue(unsigned int value, unsigned int numBits, + IntCache &cache, unsigned int blockSize = 0); + + void encodeCachedValue(unsigned char value, unsigned int numBits, + CharCache &cache, unsigned int blockSize = 0); + + void encodeDiffCachedValue(const unsigned int value, unsigned int &previous, + unsigned int numBits, IntCache &cache, + unsigned int blockSize = 0) + { + encodeCachedValue((value - 1) - previous, numBits, cache, blockSize); + + previous = value; + } + + void encodeBoolValue(unsigned int value) + { + encodeValue(value, 1); + } + + void encodeOpcodeValue(unsigned char value, OpcodeCache &cache) + { + encodeCachedValue(value, 8, cache.base_[cache.slot_], 8); + + cache.slot_ = value; + } + + void encodeActionValue(unsigned char value, ActionCache &cache) + { + unsigned short position = 0; + + encodeActionValue(value, position, cache); + } + + void encodeActionValue(unsigned char value, unsigned short position, + ActionCache &cache); + + void encodeNewXidValue(unsigned int value, unsigned int &lastId, + IntCache &lastIdCache, IntCache &cache, + FreeCache &freeCache); + + void encodeNewXidValue(unsigned int value, unsigned int &lastId, + IntCache &lastIdCache, XidCache &cache, + FreeCache &freeCache); + + void encodeXidValue(unsigned int value, XidCache &cache); + + void encodeFreeXidValue(unsigned int value, FreeCache &cache); + + void encodeTextData(const unsigned char *buffer, unsigned int numBytes) + { + encodeMemory(buffer, numBytes); + } + + void encodeIntData(const unsigned char *buffer, unsigned int numBytes) + { + encodeMemory(buffer, numBytes); + } + + void encodeLongData(const unsigned char *buffer, unsigned int numBytes) + { + encodeMemory(buffer, numBytes); + } + + void encodeMemory(const unsigned char *buffer, unsigned int numBytes); + + unsigned char *getData() + { + return buffer_; + } + + unsigned int getLength() const; + + unsigned int getBits() const + { + return ((nextDest_ - buffer_) << 3) + (7 - destShift_); + } + + unsigned int diffBits(); + + void fullReset(); + + private: + + void growBuffer(unsigned int numBytes = 0); + + void alignBuffer(); + + unsigned int size_; + unsigned char *buffer_; + + // + // This points to the first byte + // just beyond end of the buffer. + // + + const unsigned char *end_; + + unsigned char *nextDest_; + unsigned int destShift_; + unsigned int lastBits_; + + unsigned int initialSize_; + unsigned int thresholdSize_; + unsigned int maximumSize_; +}; + +#endif /* EncodeBuffer_H */ diff --git a/nxcomp/src/FillPoly.cpp b/nxcomp/src/FillPoly.cpp new file mode 100644 index 000000000..b5928d5cf --- /dev/null +++ b/nxcomp/src/FillPoly.cpp @@ -0,0 +1,239 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "FillPoly.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int FillPolyStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + FillPolyMessage *fillPoly = (FillPolyMessage *) message; + + // + // Here is the fingerprint. + // + + fillPoly -> drawable = GetULONG(buffer + 4, bigEndian); + fillPoly -> gcontext = GetULONG(buffer + 8, bigEndian); + + fillPoly -> shape = *(buffer + 12); + fillPoly -> mode = *(buffer + 13); + + // Since ProtoStep8 (#issue 108) + if (size >= (unsigned int) dataOffset) + { + fillPoly -> x_origin = GetUINT(buffer + 16, bigEndian); + fillPoly -> y_origin = GetUINT(buffer + 18, bigEndian); + } + else + { + fillPoly -> x_origin = 0; + fillPoly -> y_origin = 0; + } + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int FillPolyStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + FillPolyMessage *fillPoly = (FillPolyMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(fillPoly -> drawable, buffer + 4, bigEndian); + PutULONG(fillPoly -> gcontext, buffer + 8, bigEndian); + + *(buffer + 12) = fillPoly -> shape; + *(buffer + 13) = fillPoly -> mode; + + // Since ProtoStep8 (#issue 108) + if (size >= (unsigned int) dataOffset) + { + PutUINT(fillPoly -> x_origin, buffer + 16, bigEndian); + PutUINT(fillPoly -> y_origin, buffer + 18, bigEndian); + } + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void FillPolyStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + FillPolyMessage *fillPoly = (FillPolyMessage *) message; + + *logofs << name() << ": Identity drawable " << fillPoly -> drawable + << ", gcontext " << fillPoly -> gcontext << ", shape " + << fillPoly -> shape << ", mode " << fillPoly -> mode + << fillPoly -> size_ << ", x_origin " << fillPoly -> x_origin + << ", y_origin " << fillPoly -> y_origin << ".\n" + << logofs_flush; + #endif +} + +void FillPolyStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Fields shape, mode. + // + + md5_append(md5_state_, buffer + 12, 2); +} + +void FillPolyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + FillPolyMessage *fillPoly = (FillPolyMessage *) message; + FillPolyMessage *cachedFillPoly = (FillPolyMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << fillPoly -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(fillPoly -> drawable, clientCache -> drawableCache); + + cachedFillPoly -> drawable = fillPoly -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << fillPoly -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(fillPoly -> gcontext, clientCache -> gcCache); + + cachedFillPoly -> gcontext = fillPoly -> gcontext; + + // Since ProtoStep8 (#issue 108) + if (fillPoly -> size_ >= dataOffset) + { + #ifdef TEST + *logofs << name() << ": Encoding value " << fillPoly -> x_origin + << " as x_origin field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(fillPoly -> x_origin, 16, + *clientCache -> fillPolyXAbsCache[0], 8); + + cachedFillPoly -> x_origin = fillPoly -> x_origin; + + #ifdef TEST + *logofs << name() << ": Encoding value " << fillPoly -> y_origin + << " as y_origin field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(fillPoly -> y_origin, 16, + *clientCache -> fillPolyYAbsCache[0], 8); + + cachedFillPoly -> y_origin = fillPoly -> y_origin; + } +} + +void FillPolyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + FillPolyMessage *fillPoly = (FillPolyMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(fillPoly -> drawable, clientCache -> drawableCache); + + #ifdef TEST + *logofs << name() << ": Decoded value " << fillPoly -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(fillPoly -> gcontext, clientCache -> gcCache); + + #ifdef TEST + *logofs << name() << ": Decoded value " << fillPoly -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + // Since ProtoStep8 (#issue 108) + if (fillPoly -> size_ >= dataOffset) + { + unsigned int value; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache -> fillPolyXAbsCache[0], 8); + + fillPoly -> x_origin = value; + + #ifdef TEST + *logofs << name() << ": Decoded value " << fillPoly -> x_origin + << " as x_origin field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache -> fillPolyYAbsCache[0], 8); + + fillPoly -> y_origin = value; + + #ifdef TEST + *logofs << name() << ": Decoded value " << fillPoly -> y_origin + << " as y_origin field.\n" << logofs_flush; + #endif + } +} + + diff --git a/nxcomp/src/FillPoly.h b/nxcomp/src/FillPoly.h new file mode 100644 index 000000000..4ceb96c09 --- /dev/null +++ b/nxcomp/src/FillPoly.h @@ -0,0 +1,200 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef FillPoly_H +#define FillPoly_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define FILLPOLY_ENABLE_CACHE 1 +#define FILLPOLY_ENABLE_DATA 0 +#define FILLPOLY_ENABLE_SPLIT 0 +#define FILLPOLY_ENABLE_COMPRESS 0 + +#define FILLPOLY_DATA_LIMIT 512 + +#define FILLPOLY_CACHE_SLOTS 2000 +#define FILLPOLY_CACHE_THRESHOLD 3 +#define FILLPOLY_CACHE_LOWER_THRESHOLD 1 + +#define FILLPOLY_DATA_OFFSET_IF_PROTO_STEP_8 20 + +// +// The message class. +// + +class FillPolyMessage : public Message +{ + friend class FillPolyStore; + + public: + + FillPolyMessage() + { + } + + ~FillPolyMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char shape; + unsigned char mode; + unsigned int drawable; + unsigned int gcontext; + + unsigned short x_origin; + unsigned short y_origin; +}; + +class FillPolyStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + FillPolyStore() : MessageStore() + { + enableCache = FILLPOLY_ENABLE_CACHE; + enableData = FILLPOLY_ENABLE_DATA; + enableSplit = FILLPOLY_ENABLE_SPLIT; + enableCompress = FILLPOLY_ENABLE_COMPRESS; + + dataLimit = FILLPOLY_DATA_LIMIT; + + // Since ProtoStep8 (#issue 108) + dataOffset = FILLPOLY_DATA_OFFSET_IF_PROTO_STEP_8; + + cacheSlots = FILLPOLY_CACHE_SLOTS; + cacheThreshold = FILLPOLY_CACHE_THRESHOLD; + cacheLowerThreshold = FILLPOLY_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~FillPolyStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "FillPoly"; + } + + virtual unsigned char opcode() const + { + return X_FillPoly; + } + + virtual unsigned int storage() const + { + return sizeof(FillPolyMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new FillPolyMessage(); + } + + virtual Message *create(const Message &message) const + { + return new FillPolyMessage((const FillPolyMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (FillPolyMessage *) message; + } + + virtual int identitySize(const unsigned char *buffer, unsigned int size) + { + // Since ProtoStep8 (#issue 108) + return (size >= FILLPOLY_DATA_OFFSET_IF_PROTO_STEP_8 ? + FILLPOLY_DATA_OFFSET_IF_PROTO_STEP_8 : size); + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* FillPoly_H */ diff --git a/nxcomp/src/Fork.cpp b/nxcomp/src/Fork.cpp new file mode 100644 index 000000000..657c36134 --- /dev/null +++ b/nxcomp/src/Fork.cpp @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "Fork.h" +#include "Misc.h" +#include "Timestamp.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Only on Cygwin, retry n times waiting a +// given amount of milliseconds after each +// attempt. +// + +#define RETRY_LIMIT 30 +#define RETRY_TIMEOUT 1000 + +int Fork() +{ + #ifdef __CYGWIN32__ + + int limit = RETRY_LIMIT; + int timeout = RETRY_TIMEOUT; + + #else + + int limit = 1; + int timeout = 0; + + #endif + + int pid = 0; + + for (int i = 0; i < limit; i++) + { + #ifdef TEST + *logofs << "Fork: Trying at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + // + // It could optionally try again only if the + // error code is 11, 'Resource temporarily + // unavailable'. + // + + if ((pid = fork()) >= 0) + { + break; + } + else if (i < limit - 1) + { + #ifdef WARNING + *logofs << "Fork: WARNING! Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'. Retrying...\n" << logofs_flush; + #endif + + usleep(timeout * 1000); + } + } + + #ifdef TEST + + if (pid <= 0) + { + *logofs << "Fork: Returning at " << strMsTimestamp() + << ".\n" << logofs_flush; + } + + #endif + + return pid; +} diff --git a/nxcomp/src/Fork.h b/nxcomp/src/Fork.h new file mode 100644 index 000000000..94238ed90 --- /dev/null +++ b/nxcomp/src/Fork.h @@ -0,0 +1,31 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +// +// Try again if the fork() fails, as it can happen +// often on Cygwin. +// + +extern int Fork(); diff --git a/nxcomp/src/FreeCache.h b/nxcomp/src/FreeCache.h new file mode 100644 index 000000000..bf5c801e5 --- /dev/null +++ b/nxcomp/src/FreeCache.h @@ -0,0 +1,42 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef FreeCache_H +#define FreeCache_H + +#include "IntCache.h" + +class FreeCache : public IntCache +{ + public: + + FreeCache(unsigned int size) + + : IntCache(size) + { + } +}; + +#endif /* FreeCache_H */ diff --git a/nxcomp/src/GenericChannel.cpp b/nxcomp/src/GenericChannel.cpp new file mode 100644 index 000000000..877412cee --- /dev/null +++ b/nxcomp/src/GenericChannel.cpp @@ -0,0 +1,495 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "GenericChannel.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "StaticCompressor.h" + +#include "Statistics.h" +#include "Proxy.h" + +extern Proxy *proxy; + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Log the important tracepoints related +// to writing packets to the peer proxy. +// + +#undef FLUSH + +// +// Define this to log when a channel +// is created or destroyed. +// + +#undef REFERENCES + +// +// Here are the static members. +// + +#ifdef REFERENCES + +int GenericChannel::references_ = 0; + +#endif + +GenericChannel::GenericChannel(Transport *transport, StaticCompressor *compressor) + + : Channel(transport, compressor), readBuffer_(transport_, this) +{ + #ifdef REFERENCES + *logofs << "GenericChannel: Created new object at " + << this << " for FD#" << fd_ << " out of " + << ++references_ << " allocated channels.\n" + << logofs_flush; + #endif +} + +GenericChannel::~GenericChannel() +{ + #ifdef REFERENCES + *logofs << "GenericChannel: Deleted object at " + << this << " for FD#" << fd_ << " out of " + << --references_ << " allocated channels.\n" + << logofs_flush; + #endif +} + +// +// Beginning of handleRead(). +// + +int GenericChannel::handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, + unsigned int length) +{ + #ifdef TEST + *logofs << "handleRead: Called for FD#" << fd_ + << " with " << encodeBuffer.getLength() + << " bytes already encoded.\n" + << logofs_flush; + #endif + + // + // Pointer to located message and + // its size in bytes. + // + + const unsigned char *inputMessage; + unsigned int inputLength; + + // + // Tag message as generic data in compression + // routine. Opcode is not actually transferred + // over the network. + // + + unsigned char inputOpcode = X_NXInternalGenericData; + + #if defined(TEST) || defined(INFO) + *logofs << "handleRead: Trying to read from FD#" + << fd_ << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + int result = readBuffer_.readMessage(); + + #ifdef DEBUG + *logofs << "handleRead: Read result on FD#" << fd_ + << " is " << result << ".\n" + << logofs_flush; + #endif + + if (result < 0) + { + // + // Let the proxy close the channel. + // + + return -1; + } + else if (result == 0) + { + #if defined(TEST) || defined(INFO) + + *logofs << "handleRead: PANIC! No data read from FD#" + << fd_ << " while encoding messages.\n" + << logofs_flush; + + HandleCleanup(); + + #endif + + return 0; + } + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "handleRead: Encoding messages for FD#" << fd_ + << " with " << readBuffer_.getLength() << " bytes " + << "in the buffer.\n" << logofs_flush; + #endif + + // + // Divide the available data in multiple + // messages and encode them one by one. + // + + if (proxy -> handleAsyncSwitch(fd_) < 0) + { + return -1; + } + + while ((inputMessage = readBuffer_.getMessage(inputLength)) != NULL) + { + encodeBuffer.encodeValue(inputLength, 32, 14); + + if (isCompressed() == 1) + { + unsigned int compressedDataSize = 0; + unsigned char *compressedData = NULL; + + if (handleCompress(encodeBuffer, inputOpcode, 0, + inputMessage, inputLength, compressedData, + compressedDataSize) < 0) + { + return -1; + } + } + else + { + encodeBuffer.encodeMemory(inputMessage, inputLength); + } + + int bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleRead: Handled generic data for FD#" << fd_ + << ". " << inputLength << " bytes in, " << bits << " bits (" + << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; + #endif + + addProtocolBits(inputLength << 3, bits); + + if (isPrioritized() == 1) + { + priority_++; + } + + } // End of while ((inputMessage = readBuffer_.getMessage(inputLength)) != NULL) ... + + // + // All data has been read from the read buffer. + // We still need to mark the end of the encode + // buffer just before sending the frame. This + // allows us to accommodate multiple reads in + // a single frame. + // + + if (priority_ > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleRead: WARNING! Requesting flush " + << "because of " << priority_ << " prioritized " + << "messages for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + if (proxy -> handleAsyncPriority() < 0) + { + return -1; + } + + // + // Reset the priority flag. + // + + priority_ = 0; + } + + // + // Flush if we produced enough data. + // + + if (proxy -> canAsyncFlush() == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleRead: WARNING! Requesting flush " + << "because of enough data or timeout on the " + << "proxy link.\n" << logofs_flush; + #endif + + if (proxy -> handleAsyncFlush() < 0) + { + return -1; + } + } + + #if defined(TEST) || defined(INFO) + + if (transport_ -> pending() != 0 || + readBuffer_.checkMessage() != 0) + { + *logofs << "handleRead: PANIC! Buffer for X descriptor FD#" + << fd_ << " has " << transport_ -> pending() + << " bytes to read.\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + // + // Reset the read buffer. + // + + readBuffer_.fullReset(); + + return 1; +} + +// +// End of handleRead(). +// + +// +// Beginning of handleWrite(). +// + +int GenericChannel::handleWrite(const unsigned char *message, unsigned int length) +{ + #ifdef TEST + *logofs << "handleWrite: Called for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + // + // Create the buffer from which to + // decode messages. + // + + DecodeBuffer decodeBuffer(message, length); + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "handleWrite: Decoding messages for FD#" << fd_ + << " with " << length << " bytes in the buffer.\n" + << logofs_flush; + #endif + + unsigned char *outputMessage; + unsigned int outputLength; + + // + // Tag message as generic data + // in decompression. + // + + unsigned char outputOpcode = X_NXInternalGenericData; + + for (;;) + { + decodeBuffer.decodeValue(outputLength, 32, 14); + + if (outputLength == 0) + { + break; + } + + if (isCompressed() == 1) + { + if (writeBuffer_.getAvailable() < outputLength || + (int) outputLength >= control -> TransportFlushBufferSize) + { + #ifdef DEBUG + *logofs << "handleWrite: Using scratch buffer for " + << "generic data with size " << outputLength << " and " + << writeBuffer_.getLength() << " bytes in buffer.\n" + << logofs_flush; + #endif + + outputMessage = writeBuffer_.addScratchMessage(outputLength); + } + else + { + outputMessage = writeBuffer_.addMessage(outputLength); + } + + const unsigned char *compressedData = NULL; + unsigned int compressedDataSize = 0; + + int decompressed = handleDecompress(decodeBuffer, outputOpcode, 0, + outputMessage, outputLength, compressedData, + compressedDataSize); + if (decompressed < 0) + { + return -1; + } + } + else + { + #ifdef DEBUG + *logofs << "handleWrite: Using scratch buffer for " + << "generic data with size " << outputLength << " and " + << writeBuffer_.getLength() << " bytes in buffer.\n" + << logofs_flush; + #endif + + writeBuffer_.addScratchMessage((unsigned char *) + decodeBuffer.decodeMemory(outputLength), outputLength); + } + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleWrite: Handled generic data for FD#" << fd_ + << ". " << outputLength << " bytes out.\n" + << logofs_flush; + #endif + + handleFlush(flush_if_needed); + } + + // + // Write any remaining data to socket. + // + + if (handleFlush(flush_if_any) < 0) + { + return -1; + } + + return 1; +} + +// +// End of handleWrite(). +// + +// +// Other members. +// + +int GenericChannel::handleCompletion(EncodeBuffer &encodeBuffer) +{ + // + // Add the bits telling to the remote + // that all data in the frame has been + // encoded. + // + + if (encodeBuffer.getLength() > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleCompletion: Writing completion bits with " + << encodeBuffer.getLength() << " bytes encoded " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeValue(0, 32, 14); + + return 1; + } + #if defined(TEST) || defined(INFO) + else + { + *logofs << "handleCompletion: PANIC! No completion to write " + << "for FD#" << fd_ << ".\n" << logofs_flush; + + HandleCleanup(); + } + #endif + + return 0; +} + +int GenericChannel::handleConfiguration() +{ + #ifdef TEST + *logofs << "GenericChannel: Setting new buffer parameters.\n" + << logofs_flush; + #endif + + readBuffer_.setSize(control -> GenericInitialReadSize, + control -> GenericMaximumBufferSize); + + writeBuffer_.setSize(control -> TransportGenericBufferSize, + control -> TransportGenericBufferThreshold, + control -> TransportMaximumBufferSize); + + transport_ -> setSize(control -> TransportGenericBufferSize, + control -> TransportGenericBufferThreshold, + control -> TransportMaximumBufferSize); + + return 1; +} + +int GenericChannel::handleFinish() +{ + #ifdef TEST + *logofs << "GenericChannel: Finishing channel for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + congestion_ = 0; + priority_ = 0; + + finish_ = 1; + + transport_ -> fullReset(); + + return 1; +} + +int GenericChannel::setReferences() +{ + #ifdef TEST + *logofs << "GenericChannel: Initializing the static " + << "members for the generic channels.\n" + << logofs_flush; + #endif + + #ifdef REFERENCES + + references_ = 0; + + #endif + + return 1; +} diff --git a/nxcomp/src/GenericChannel.h b/nxcomp/src/GenericChannel.h new file mode 100644 index 000000000..3df18f444 --- /dev/null +++ b/nxcomp/src/GenericChannel.h @@ -0,0 +1,440 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef GenericChannel_H +#define GenericChannel_H + +#include "Channel.h" + +#include "Statistics.h" + +#include "GenericReadBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#undef TEST +#undef DEBUG + +// +// Define this to log a line when a channel +// is created or destroyed. +// + +#undef REFERENCES + +// +// This class implements the client +// side compression of X protocol. +// + +class GenericChannel : public Channel +{ + public: + + GenericChannel(Transport *transport, StaticCompressor *compressor); + + virtual ~GenericChannel(); + + virtual int handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, + unsigned int length); + + virtual int handleWrite(const unsigned char *message, unsigned int length); + + + virtual int handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, + T_store_action action, int position, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) + { + return 0; + } + + virtual int handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, + T_store_action action, int position, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) + { + return 0; + } + + + virtual int handleSplit(EncodeBuffer &encodeBuffer) + { + return 0; + } + + virtual int handleSplit(DecodeBuffer &decodeBuffer) + { + return 0; + } + + virtual int handleSplitEvent(EncodeBuffer &encodeBuffer, Split *split) + { + return 0; + } + + virtual int handleSplitEvent(DecodeBuffer &decodeBuffer) + { + return 0; + } + + virtual int handleMotion(EncodeBuffer &encodeBuffer) + { + return 0; + } + + virtual int handleCompletion(EncodeBuffer &encodeBuffer); + + virtual int handleConfiguration(); + + virtual int handleFinish(); + + virtual int handleAsyncEvents() + { + return 0; + } + + virtual int needSplit() const + { + return 0; + } + + virtual int needMotion() const + { + return 0; + } + + virtual T_channel_type getType() const = 0; + + // + // Initialize the static members. + // + + static int setReferences(); + + protected: + + // + // Generic channels are considered to be + // in congestion state as soon as the + // socket is blocked for write. + // + + virtual int isCongested() + { + return (transport_ -> blocked() == 1); + } + + virtual int isReliable() + { + return 0; + } + + // + // Model generic channels' encoding and + // decoding policy. + // + + virtual int isCompressed() = 0; + + // + // Return true if the channel contains + // time sensitive data. + // + + virtual int isPrioritized() = 0; + + // + // Record the protocol bits for the + // specific service. + // + + virtual void addProtocolBits(unsigned int bitsIn, unsigned int bitsOut) = 0; + + // + // Channel's own read buffer. + // + + GenericReadBuffer readBuffer_; + + private: + + // + // Keep track of object's creation + // and deletion. + // + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +class CupsChannel : public GenericChannel +{ + public: + + CupsChannel(Transport *transport, StaticCompressor *compressor) + + : GenericChannel(transport, compressor) + { + } + + virtual ~CupsChannel() + { + } + + protected: + + virtual T_channel_type getType() const + { + return channel_cups; + } + + virtual int isCompressed() + { + // Since ProtoStep8 (#issue 108) + return 0; + } + + virtual int isPrioritized() + { + return 0; + } + + virtual void addProtocolBits(unsigned int bitsIn, + unsigned int bitsOut) + { + statistics -> addCupsBits(bitsIn, bitsOut); + } +}; + +class SmbChannel : public GenericChannel +{ + public: + + SmbChannel(Transport *transport, StaticCompressor *compressor) + + : GenericChannel(transport, compressor) + { + } + + virtual ~SmbChannel() + { + } + + protected: + + virtual T_channel_type getType() const + { + return channel_smb; + } + + virtual int isCompressed() + { + // Since ProtoStep8 (#issue 108) + return 0; + } + + virtual int isPrioritized() + { + return 0; + } + + virtual void addProtocolBits(unsigned int bitsIn, + unsigned int bitsOut) + { + statistics -> addSmbBits(bitsIn, bitsOut); + } +}; + +class MediaChannel : public GenericChannel +{ + public: + + MediaChannel(Transport *transport, StaticCompressor *compressor) + + : GenericChannel(transport, compressor) + { + } + + virtual ~MediaChannel() + { + } + + protected: + + virtual T_channel_type getType() const + { + return channel_media; + } + + // + // Don't try to compress the media data. + // + + virtual int isCompressed() + { + return 0; + } + + // + // Reduce the latency of media channels + // by setting them as prioritized, even + // if this will take away bandwidth from + // the X channels. + // + + virtual int isPrioritized() + { + return 1; + } + + virtual void addProtocolBits(unsigned int bitsIn, + unsigned int bitsOut) + { + statistics -> addMediaBits(bitsIn, bitsOut); + } +}; + +class HttpChannel : public GenericChannel +{ + public: + + HttpChannel(Transport *transport, StaticCompressor *compressor) + + : GenericChannel(transport, compressor) + { + } + + virtual ~HttpChannel() + { + } + + protected: + + virtual T_channel_type getType() const + { + return channel_http; + } + + virtual int isCompressed() + { + // Since ProtoStep8 (#issue 108) + return 0; + } + + virtual int isPrioritized() + { + return 0; + } + + virtual void addProtocolBits(unsigned int bitsIn, + unsigned int bitsOut) + { + statistics -> addHttpBits(bitsIn, bitsOut); + } +}; + +class FontChannel : public GenericChannel +{ + public: + + FontChannel(Transport *transport, StaticCompressor *compressor) + + : GenericChannel(transport, compressor) + { + } + + virtual ~FontChannel() + { + } + + protected: + + virtual T_channel_type getType() const + { + return channel_font; + } + + virtual int isCompressed() + { + // Since ProtoStep8 (#issue 108) + return 0; + } + + virtual int isPrioritized() + { + return 1; + } + + virtual void addProtocolBits(unsigned int bitsIn, + unsigned int bitsOut) + { + statistics -> addFontBits(bitsIn, bitsOut); + } +}; + +class SlaveChannel : public GenericChannel +{ + public: + + SlaveChannel(Transport *transport, StaticCompressor *compressor) + + : GenericChannel(transport, compressor) + { + } + + virtual ~SlaveChannel() + { + } + + protected: + + virtual T_channel_type getType() const + { + return channel_slave; + } + + virtual int isCompressed() + { + return 0; + } + + virtual int isPrioritized() + { + return 0; + } + + virtual void addProtocolBits(unsigned int bitsIn, + unsigned int bitsOut) + { + statistics -> addSlaveBits(bitsIn, bitsOut); + } +}; + +#endif /* GenericChannel_H */ diff --git a/nxcomp/src/GenericReadBuffer.cpp b/nxcomp/src/GenericReadBuffer.cpp new file mode 100644 index 000000000..78217157e --- /dev/null +++ b/nxcomp/src/GenericReadBuffer.cpp @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "GenericReadBuffer.h" + +#include "GenericChannel.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +unsigned int GenericReadBuffer::suggestedLength(unsigned int pendingLength) +{ + // + // Always read the initial read size. + // + + return 0; +} + +int GenericReadBuffer::locateMessage(const unsigned char *start, + const unsigned char *end, + unsigned int &controlLength, + unsigned int &dataLength, + unsigned int &trailerLength) +{ + // + // We don't care about the endianess + // in generic channels. + // + + unsigned int size = end - start; + + #ifdef TEST + *logofs << "GenericReadBuffer: Locating message for FD#" + << transport_ -> fd() << " with " << size + << " bytes.\n" << logofs_flush; + #endif + + if (size == 0) + { + remaining_ = 1; + + return 0; + } + + dataLength = size; + + controlLength = 0; + trailerLength = 0; + + remaining_ = 0; + + return 1; +} diff --git a/nxcomp/src/GenericReadBuffer.h b/nxcomp/src/GenericReadBuffer.h new file mode 100644 index 000000000..5ea4d939d --- /dev/null +++ b/nxcomp/src/GenericReadBuffer.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef GenericReadBuffer_H +#define GenericReadBuffer_H + +#include "ReadBuffer.h" +#include "Control.h" + +class GenericChannel; + +class GenericReadBuffer : public ReadBuffer +{ + public: + + GenericReadBuffer(Transport *transport, GenericChannel *channel) + + : ReadBuffer(transport), channel_(channel) + { + } + + virtual ~GenericReadBuffer() + { + } + + protected: + + virtual unsigned int suggestedLength(unsigned int pendingLength); + + virtual int locateMessage(const unsigned char *start, + const unsigned char *end, + unsigned int &controlLength, + unsigned int &dataLength, + unsigned int &trailerLength); + + GenericChannel *channel_; +}; + +#endif /* GenericReadBuffer_H */ diff --git a/nxcomp/src/GenericReply.cpp b/nxcomp/src/GenericReply.cpp new file mode 100644 index 000000000..b56e579e8 --- /dev/null +++ b/nxcomp/src/GenericReply.cpp @@ -0,0 +1,302 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "GenericReply.h" + +#include "ServerCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +GenericReplyStore::GenericReplyStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = GENERICREPLY_ENABLE_CACHE; + enableData = GENERICREPLY_ENABLE_DATA; + enableSplit = GENERICREPLY_ENABLE_SPLIT; + + // Since ProtoStep7 (#issue 108) + enableCompress = GENERICREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = GENERICREPLY_DATA_LIMIT; + dataOffset = GENERICREPLY_DATA_OFFSET; + + cacheSlots = GENERICREPLY_CACHE_SLOTS; + cacheThreshold = GENERICREPLY_CACHE_THRESHOLD; + cacheLowerThreshold = GENERICREPLY_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +GenericReplyStore::~GenericReplyStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int GenericReplyStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ServerCache *serverCache = (ServerCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message identity.\n" + << logofs_flush; + #endif + + encodeBuffer.encodeValue(GetULONG(buffer + 4, bigEndian), 32, 15); + + encodeBuffer.encodeCachedValue(*(buffer + 1), 8, + serverCache -> genericReplyCharCache); + + for (unsigned int i = 0; i < 6; i++) + { + encodeBuffer.encodeCachedValue(GetULONG(buffer + i * 4 + 8, bigEndian), 32, + *serverCache -> genericReplyIntCache[i]); + } + + #ifdef DEBUG + *logofs << name() << ": Encoded full message identity.\n" + << logofs_flush; + #endif + + return 1; +} + +int GenericReplyStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ServerCache *serverCache = (ServerCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message identity.\n" + << logofs_flush; + #endif + + decodeBuffer.decodeValue(size, 32, 15); + + size = 32 + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + decodeBuffer.decodeCachedValue(*(buffer + 1), 8, + serverCache -> genericReplyCharCache); + + unsigned int value; + + for (unsigned int i = 0; i < 6; i++) + { + decodeBuffer.decodeCachedValue(value, 32, + *serverCache -> genericReplyIntCache[i]); + + PutULONG(value, buffer + i * 4 + 8, bigEndian); + } + + #ifdef DEBUG + *logofs << name() << ": Decoded full message identity.\n" + << logofs_flush; + #endif + + return 1; +} + +int GenericReplyStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GenericReplyMessage *genericReply = (GenericReplyMessage *) message; + + genericReply -> byte_data = *(buffer + 1); + + for (int i = 0; i < 12; i++) + { + genericReply -> short_data[i] = GetUINT(buffer + i * 2 + 8, bigEndian); + } + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int GenericReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GenericReplyMessage *genericReply = (GenericReplyMessage *) message; + + *(buffer + 1) = genericReply -> byte_data; + + for (int i = 0; i < 12; i++) + { + PutUINT(genericReply -> short_data[i], buffer + i * 2 + 8, bigEndian); + } + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void GenericReplyStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + GenericReplyMessage *genericReply = (GenericReplyMessage *) message; + + *logofs << name() << ": Identity byte_data " + << (unsigned) genericReply -> byte_data; + + for (int i = 0; i < 12; i++) + { + *logofs << ", short_data[" << i << "]" + << (unsigned) genericReply -> short_data[i]; + } + + *logofs << ", size " << genericReply -> size_ << ".\n"; + + #endif +} + +void GenericReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +} + +void GenericReplyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + // + // Encode the variant part. + // + + GenericReplyMessage *genericReply = (GenericReplyMessage *) message; + GenericReplyMessage *cachedGenericReply = (GenericReplyMessage *) cachedMessage; + + ServerCache *serverCache = (ServerCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " + << (unsigned int) genericReply -> byte_data + << " as byte_data field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(genericReply -> byte_data, 8, + serverCache -> genericReplyCharCache); + + cachedGenericReply -> byte_data = genericReply -> byte_data; + + for (unsigned int i = 0; i < 12; i++) + { + #ifdef TEST + *logofs << name() << ": Encoding value " << genericReply -> short_data[i] + << " as short_data[" << i << "] field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(genericReply -> short_data[i], 16, + *serverCache -> genericReplyIntCache[i]); + + cachedGenericReply -> short_data[i] = genericReply -> short_data[i]; + } +} + +void GenericReplyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + // + // Decode the variant part. + // + + GenericReplyMessage *genericReply = (GenericReplyMessage *) message; + + ServerCache *serverCache = (ServerCache *) channelCache; + + decodeBuffer.decodeCachedValue(genericReply -> byte_data, 8, + serverCache -> genericReplyCharCache); + + #ifdef TEST + *logofs << name() << ": Decoded value " + << (unsigned int) genericReply -> byte_data + << " as byte_data field.\n" << logofs_flush; + #endif + + unsigned int value; + + for (unsigned int i = 0; i < 12; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *serverCache -> genericReplyIntCache[i]); + + genericReply -> short_data[i] = (unsigned short) value; + + #ifdef TEST + *logofs << name() << ": Decoded value " << genericReply -> short_data[i] + << " as short_data[" << i << "] field.\n" << logofs_flush; + #endif + } +} diff --git a/nxcomp/src/GenericReply.h b/nxcomp/src/GenericReply.h new file mode 100644 index 000000000..e899b8467 --- /dev/null +++ b/nxcomp/src/GenericReply.h @@ -0,0 +1,161 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef GenericReply_H +#define GenericReply_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define GENERICREPLY_ENABLE_CACHE 1 +#define GENERICREPLY_ENABLE_DATA 1 +#define GENERICREPLY_ENABLE_SPLIT 0 + +#define GENERICREPLY_DATA_LIMIT 1048576 - 32 +#define GENERICREPLY_DATA_OFFSET 32 + +#define GENERICREPLY_CACHE_SLOTS 400 +#define GENERICREPLY_CACHE_THRESHOLD 5 +#define GENERICREPLY_CACHE_LOWER_THRESHOLD 1 + +#define GENERICREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +// +// The message class. +// + +class GenericReplyMessage : public Message +{ + friend class GenericReplyStore; + + public: + + GenericReplyMessage() + { + } + + ~GenericReplyMessage() + { + } + + // + // Put here the fields which constitute the + // 'identity' part of the message. Starting + // from protocol level 3 we use short data + // to increase cache efficiency. + // + + private: + + unsigned char byte_data; + unsigned int int_data[6]; + unsigned short short_data[12]; +}; + +class GenericReplyStore : public MessageStore +{ + public: + + GenericReplyStore(StaticCompressor *compressor); + + virtual ~GenericReplyStore(); + + virtual const char *name() const + { + return "GenericReply"; + } + + virtual unsigned char opcode() const + { + return X_NXInternalGenericReply; + } + + virtual unsigned int storage() const + { + return sizeof(GenericReplyMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new GenericReplyMessage(); + } + + virtual Message *create(const Message &message) const + { + return new GenericReplyMessage((const GenericReplyMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (GenericReplyMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* GenericReply_H */ diff --git a/nxcomp/src/GenericRequest.cpp b/nxcomp/src/GenericRequest.cpp new file mode 100644 index 000000000..c569d6a24 --- /dev/null +++ b/nxcomp/src/GenericRequest.cpp @@ -0,0 +1,334 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "GenericRequest.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +GenericRequestStore::GenericRequestStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = GENERICREQUEST_ENABLE_CACHE; + enableData = GENERICREQUEST_ENABLE_DATA; + enableSplit = GENERICREQUEST_ENABLE_SPLIT; + + // Since ProtoStep7 (#issue 108) + enableCompress = GENERICREQUEST_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = GENERICREQUEST_DATA_LIMIT; + dataOffset = GENERICREQUEST_DATA_OFFSET; + + cacheSlots = GENERICREQUEST_CACHE_SLOTS; + cacheThreshold = GENERICREQUEST_CACHE_THRESHOLD; + cacheLowerThreshold = GENERICREQUEST_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +GenericRequestStore::~GenericRequestStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int GenericRequestStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; + #endif + + encodeBuffer.encodeValue(size >> 2, 16, 10); + + encodeBuffer.encodeCachedValue(*(buffer + 1), 8, + clientCache -> genericRequestOpcodeCache); + + for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) + { + #ifdef DEBUG + *logofs << name() << ": Encoding data[" << i << "] " + << "at position " << i * 2 + 4 << " with value " + << GetUINT(buffer + (i * 2) + 4, bigEndian) + << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(GetUINT(buffer + (i * 2) + 4, bigEndian), 16, + *clientCache -> genericRequestDataCache[i]); + } + + #ifdef DEBUG + *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int GenericRequestStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; + #endif + + decodeBuffer.decodeValue(size, 16, 10); + + size <<= 2; + + buffer = writeBuffer -> addMessage(size); + + decodeBuffer.decodeCachedValue(*(buffer + 1), 8, + clientCache -> genericRequestOpcodeCache); + + unsigned int value; + + for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache -> genericRequestDataCache[i]); + + #ifdef DEBUG + *logofs << name() << ": Decoding data[" << i << "] " + << "at position " << i * 2 + 4 << " with value " + << value << ".\n" << logofs_flush; + #endif + + PutUINT(value, buffer + 4 + (i * 2), bigEndian); + } + + #ifdef DEBUG + *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int GenericRequestStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; + + genericRequest -> opcode = *(buffer + 1); + + for (unsigned int i = 0; i < 8; i++) + { + if ((i * 2 + 4) < size) + { + genericRequest -> data[i] = GetUINT(buffer + i * 2 + 4, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed data[" << i << "] " + << "with value " << genericRequest -> data[i] + << ".\n" << logofs_flush; + #endif + } + else + { + genericRequest -> data[i] = 0; + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int GenericRequestStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; + + *(buffer + 1) = genericRequest -> opcode; + + for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) + { + #ifdef DEBUG + *logofs << name() << ": Unparsed data[" << i << "] " + << "with value " << genericRequest -> data[i] + << ".\n" << logofs_flush; + #endif + + PutUINT(genericRequest -> data[i], buffer + i * 2 + 4, bigEndian); + } + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void GenericRequestStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; + + *logofs << name() << ": Identity opcode " << (unsigned) genericRequest -> opcode; + + for (int i = 0; i < 8; i++) + { + *logofs << ", data[" << i << "] " << genericRequest -> data[i]; + } + + *logofs << ", size " << genericRequest -> size_ << ".\n" << logofs_flush; + + #endif +} + +void GenericRequestStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // As data offset can be beyond the real end of + // the message, we need to include the message's + // size or we will match any message whose size + // is less or equal to the data offset. + // + + md5_append(md5_state_, buffer + 2, 2); +} + +void GenericRequestStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + // + // Encode the variant part. + // + + GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; + GenericRequestMessage *cachedGenericRequest = (GenericRequestMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Updating value " + << (unsigned) genericRequest -> opcode + << " as opcode field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue((unsigned int) genericRequest -> opcode, 8, + clientCache -> genericRequestOpcodeCache); + + cachedGenericRequest -> opcode = genericRequest -> opcode; + + for (int i = 0; i < 8 && (i * 2 + 4) < genericRequest -> size_; i++) + { + #ifdef TEST + *logofs << name() << ": Updating data[" << i << "] " + << "with value " << genericRequest -> data[i] + << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue((unsigned int) genericRequest -> data[i], 16, + *clientCache -> genericRequestDataCache[i]); + + cachedGenericRequest -> data[i] = genericRequest -> data[i]; + } +} + +void GenericRequestStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + GenericRequestMessage *genericRequest = (GenericRequestMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(genericRequest -> opcode, 8, + clientCache -> genericRequestOpcodeCache); + + #ifdef TEST + *logofs << name() << ": Updated value " + << (unsigned) genericRequest -> opcode + << " as opcode field.\n" << logofs_flush; + #endif + + unsigned int value; + + for (int i = 0; i < 8 && (i * 2 + 4) < genericRequest -> size_; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache -> genericRequestDataCache[i]); + + genericRequest -> data[i] = (unsigned short) value; + + #ifdef TEST + *logofs << name() << ": Updated data[" << i << "] " + << "with value " << genericRequest -> data[i] + << ".\n" << logofs_flush; + #endif + } +} diff --git a/nxcomp/src/GenericRequest.h b/nxcomp/src/GenericRequest.h new file mode 100644 index 000000000..13ffea718 --- /dev/null +++ b/nxcomp/src/GenericRequest.h @@ -0,0 +1,160 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef GenericRequest_H +#define GenericRequest_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define GENERICREQUEST_ENABLE_CACHE 1 +#define GENERICREQUEST_ENABLE_DATA 1 +#define GENERICREQUEST_ENABLE_SPLIT 0 + +#define GENERICREQUEST_DATA_LIMIT 262144 - 20 +#define GENERICREQUEST_DATA_OFFSET 20 + +#define GENERICREQUEST_CACHE_SLOTS 400 +#define GENERICREQUEST_CACHE_THRESHOLD 5 +#define GENERICREQUEST_CACHE_LOWER_THRESHOLD 1 + +#define GENERICREQUEST_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +// +// The message class. +// + +class GenericRequestMessage : public Message +{ + friend class GenericRequestStore; + + public: + + GenericRequestMessage() + { + } + + ~GenericRequestMessage() + { + } + + // + // Note that we consider for this message a data offset + // of 4 (or 20 starting from protocol 3). Bytes from 9 + // to 20, if present, are taken as part of identity and + // encoded through an array of int caches. + // + + private: + + unsigned char opcode; + unsigned short data[8]; +}; + +class GenericRequestStore : public MessageStore +{ + public: + + GenericRequestStore(StaticCompressor *compressor); + + virtual ~GenericRequestStore(); + + virtual const char *name() const + { + return "GenericRequest"; + } + + virtual unsigned char opcode() const + { + return X_NXInternalGenericRequest; + } + + virtual unsigned int storage() const + { + return sizeof(GenericRequestMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new GenericRequestMessage(); + } + + virtual Message *create(const Message &message) const + { + return new GenericRequestMessage((const GenericRequestMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (GenericRequestMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* GenericRequest_H */ diff --git a/nxcomp/src/GetImage.cpp b/nxcomp/src/GetImage.cpp new file mode 100644 index 000000000..20b6a07d1 --- /dev/null +++ b/nxcomp/src/GetImage.cpp @@ -0,0 +1,177 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "GetImage.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int GetImageStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GetImageMessage *getImage = (GetImageMessage *) message; + + // + // Here is the fingerprint. + // + + getImage -> format = *(buffer + 1); + + #ifdef TEST + if (getImage -> format != 1 && getImage -> format != 2) + { + *logofs << name() << ": WARNING! Dirty value " << getImage -> format + << " for field format.\n" << logofs_flush; + } + #endif + + getImage -> drawable = GetULONG(buffer + 4, bigEndian); + + getImage -> x = GetUINT(buffer + 8, bigEndian); + getImage -> y = GetUINT(buffer + 10, bigEndian); + getImage -> width = GetUINT(buffer + 12, bigEndian); + getImage -> height = GetUINT(buffer + 14, bigEndian); + + getImage -> plane_mask = GetULONG(buffer + 16, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int GetImageStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GetImageMessage *getImage = (GetImageMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = getImage -> format; + + PutULONG(getImage -> drawable, buffer + 4, bigEndian); + + PutUINT(getImage -> x, buffer + 8, bigEndian); + PutUINT(getImage -> y, buffer + 10, bigEndian); + PutUINT(getImage -> width, buffer + 12, bigEndian); + PutUINT(getImage -> height, buffer + 14, bigEndian); + + PutULONG(getImage -> plane_mask, buffer + 16, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void GetImageStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + GetImageMessage *getImage = (GetImageMessage *) message; + + *logofs << name() << ": Identity format " << (unsigned) getImage -> format + << ", drawable " << getImage -> drawable << ", x " << getImage -> x + << ", y " << getImage -> y << ", width " << getImage -> width + << ", height " << getImage -> height << ", plane_mask " + << getImage -> plane_mask << ", size " << getImage -> size_ + << ".\n" << logofs_flush; + + #endif +} + +void GetImageStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 1, 1); + md5_append(md5_state_, buffer + 8, 2); + md5_append(md5_state_, buffer + 10, 2); + md5_append(md5_state_, buffer + 12, 2); + md5_append(md5_state_, buffer + 14, 2); + md5_append(md5_state_, buffer + 16, 4); +} + +void GetImageStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + GetImageMessage *getImage = (GetImageMessage *) message; + GetImageMessage *cachedGetImage = (GetImageMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << getImage -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(getImage -> drawable, clientCache -> drawableCache); + + cachedGetImage -> drawable = getImage -> drawable; +} + +void GetImageStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + GetImageMessage *getImage = (GetImageMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + getImage -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << getImage -> drawable + << " as drawable field.\n" << logofs_flush; + #endif +} + diff --git a/nxcomp/src/GetImage.h b/nxcomp/src/GetImage.h new file mode 100644 index 000000000..1c3558d14 --- /dev/null +++ b/nxcomp/src/GetImage.h @@ -0,0 +1,190 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef GetImage_H +#define GetImage_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define GETIMAGE_ENABLE_CACHE 1 +#define GETIMAGE_ENABLE_DATA 0 +#define GETIMAGE_ENABLE_SPLIT 0 +#define GETIMAGE_ENABLE_COMPRESS 0 + +#define GETIMAGE_DATA_LIMIT 0 +#define GETIMAGE_DATA_OFFSET 20 + +#define GETIMAGE_CACHE_SLOTS 200 +#define GETIMAGE_CACHE_THRESHOLD 1 +#define GETIMAGE_CACHE_LOWER_THRESHOLD 0 + +// +// The message class. +// + +class GetImageMessage : public Message +{ + friend class GetImageStore; + + public: + + GetImageMessage() + { + } + + ~GetImageMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char format; + unsigned int drawable; + unsigned short int x; + unsigned short int y; + unsigned short int width; + unsigned short int height; + unsigned int plane_mask; +}; + +class GetImageStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + GetImageStore() : MessageStore() + { + enableCache = GETIMAGE_ENABLE_CACHE; + enableData = GETIMAGE_ENABLE_DATA; + enableSplit = GETIMAGE_ENABLE_SPLIT; + enableCompress = GETIMAGE_ENABLE_COMPRESS; + + dataLimit = GETIMAGE_DATA_LIMIT; + dataOffset = GETIMAGE_DATA_OFFSET; + + cacheSlots = GETIMAGE_CACHE_SLOTS; + cacheThreshold = GETIMAGE_CACHE_THRESHOLD; + cacheLowerThreshold = GETIMAGE_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~GetImageStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "GetImage"; + } + + virtual unsigned char opcode() const + { + return X_GetImage; + } + + virtual unsigned int storage() const + { + return sizeof(GetImageMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new GetImageMessage(); + } + + virtual Message *create(const Message &message) const + { + return new GetImageMessage((const GetImageMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (GetImageMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* GetImage_H */ diff --git a/nxcomp/src/GetImageReply.cpp b/nxcomp/src/GetImageReply.cpp new file mode 100644 index 000000000..5100804ab --- /dev/null +++ b/nxcomp/src/GetImageReply.cpp @@ -0,0 +1,194 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "GetImageReply.h" + +#include "ServerCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +GetImageReplyStore::GetImageReplyStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = GETIMAGEREPLY_ENABLE_CACHE; + enableData = GETIMAGEREPLY_ENABLE_DATA; + enableSplit = GETIMAGEREPLY_ENABLE_SPLIT; + + // Since ProtoStep7 (#issue 108) + enableCompress = GETIMAGEREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = GETIMAGEREPLY_DATA_LIMIT; + dataOffset = GETIMAGEREPLY_DATA_OFFSET; + + cacheSlots = GETIMAGEREPLY_CACHE_SLOTS; + cacheThreshold = GETIMAGEREPLY_CACHE_THRESHOLD; + cacheLowerThreshold = GETIMAGEREPLY_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +GetImageReplyStore::~GetImageReplyStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int GetImageReplyStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; + + // + // Here is the fingerprint. + // + + getImageReply -> depth = *(buffer + 1); + + getImageReply -> visual = GetULONG(buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int GetImageReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = getImageReply -> depth; + + PutULONG(getImageReply -> visual, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void GetImageReplyStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; + + *logofs << name() << ": Identity depth " << (unsigned) getImageReply -> depth + << ", visual " << getImageReply -> visual << ", size " + << getImageReply -> size_ << ".\n"; + + #endif +} + +void GetImageReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Field depth. + // + + md5_append(md5_state_, buffer + 1, 1); +} + +void GetImageReplyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + // + // Encode the variant part. + // + + GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; + + ServerCache *serverCache = (ServerCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << getImageReply -> visual + << " as visual field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(getImageReply -> visual, 29, + serverCache -> visualCache); +} + +void GetImageReplyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + // + // Decode the variant part. + // + + GetImageReplyMessage *getImageReply = (GetImageReplyMessage *) message; + + ServerCache *serverCache = (ServerCache *) channelCache; + + decodeBuffer.decodeCachedValue(getImageReply -> visual, 29, + serverCache -> visualCache); +} diff --git a/nxcomp/src/GetImageReply.h b/nxcomp/src/GetImageReply.h new file mode 100644 index 000000000..d4f7c4267 --- /dev/null +++ b/nxcomp/src/GetImageReply.h @@ -0,0 +1,150 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef GetImageReply_H +#define GetImageReply_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define GETIMAGEREPLY_ENABLE_CACHE 1 +#define GETIMAGEREPLY_ENABLE_DATA 1 +#define GETIMAGEREPLY_ENABLE_SPLIT 0 + +#define GETIMAGEREPLY_DATA_LIMIT 1048576 - 32 +#define GETIMAGEREPLY_DATA_OFFSET 32 + +#define GETIMAGEREPLY_CACHE_SLOTS 1000 +#define GETIMAGEREPLY_CACHE_THRESHOLD 20 +#define GETIMAGEREPLY_CACHE_LOWER_THRESHOLD 2 + +#define GETIMAGEREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +// +// The message class. +// + +class GetImageReplyMessage : public Message +{ + friend class GetImageReplyStore; + + public: + + GetImageReplyMessage() + { + } + + ~GetImageReplyMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char depth; + unsigned int visual; +}; + +class GetImageReplyStore : public MessageStore +{ + public: + + GetImageReplyStore(StaticCompressor *compressor); + + virtual ~GetImageReplyStore(); + + virtual const char *name() const + { + return "GetImageReply"; + } + + virtual unsigned char opcode() const + { + return X_GetImage; + } + + virtual unsigned int storage() const + { + return sizeof(GetImageReplyMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new GetImageReplyMessage(); + } + + virtual Message *create(const Message &message) const + { + return new GetImageReplyMessage((const GetImageReplyMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (GetImageReplyMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* GetImageReply_H */ diff --git a/nxcomp/src/GetProperty.cpp b/nxcomp/src/GetProperty.cpp new file mode 100644 index 000000000..1c5e77ccc --- /dev/null +++ b/nxcomp/src/GetProperty.cpp @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "GetProperty.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int GetPropertyStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GetPropertyMessage *getProperty = (GetPropertyMessage *) message; + + // + // Here is the fingerprint. + // + + getProperty -> property_delete = *(buffer + 1); + + getProperty -> window = GetULONG(buffer + 4, bigEndian); + getProperty -> property = GetULONG(buffer + 8, bigEndian); + getProperty -> type = GetULONG(buffer + 12, bigEndian); + getProperty -> long_offset = GetULONG(buffer + 16, bigEndian); + getProperty -> long_length = GetULONG(buffer + 20, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int GetPropertyStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + + GetPropertyMessage *getProperty = (GetPropertyMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = getProperty -> property_delete; + + PutULONG(getProperty -> window, buffer + 4, bigEndian); + PutULONG(getProperty -> property, buffer + 8, bigEndian); + PutULONG(getProperty -> type, buffer + 12, bigEndian); + PutULONG(getProperty -> long_offset, buffer + 16, bigEndian); + PutULONG(getProperty -> long_length, buffer + 20, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void GetPropertyStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + GetPropertyMessage *getProperty = (GetPropertyMessage *) message; + + *logofs << name() << ": Identity property_delete " << (unsigned int) getProperty -> property_delete + << ", window " << getProperty -> window << ", property " << getProperty -> property + << ", type " << getProperty -> type << ", long-offset " << getProperty -> long_offset + << ", long-length " << getProperty -> long_length << ".\n" << logofs_flush; + + #endif +} + +void GetPropertyStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 1, 1); + md5_append(md5_state_, buffer + 4, 20); +} diff --git a/nxcomp/src/GetProperty.h b/nxcomp/src/GetProperty.h new file mode 100644 index 000000000..46727280b --- /dev/null +++ b/nxcomp/src/GetProperty.h @@ -0,0 +1,183 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef GetProperty_H +#define GetProperty_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define GETPROPERTY_ENABLE_CACHE 1 +#define GETPROPERTY_ENABLE_DATA 0 +#define GETPROPERTY_ENABLE_SPLIT 0 +#define GETPROPERTY_ENABLE_COMPRESS 0 + +#define GETPROPERTY_DATA_LIMIT 0 +#define GETPROPERTY_DATA_OFFSET 24 + +#define GETPROPERTY_CACHE_SLOTS 2000 +#define GETPROPERTY_CACHE_THRESHOLD 2 +#define GETPROPERTY_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class GetPropertyMessage : public Message +{ + friend class GetPropertyStore; + + public: + + GetPropertyMessage() + { + } + + ~GetPropertyMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char property_delete; + unsigned long window; + unsigned long property; + unsigned long type; + unsigned long long_offset; + unsigned long long_length; +}; + +class GetPropertyStore : public MessageStore +{ + + // + // Constructors and destructors. + // + + public: + + GetPropertyStore() : MessageStore() + { + enableCache = GETPROPERTY_ENABLE_CACHE; + enableData = GETPROPERTY_ENABLE_DATA; + enableSplit = GETPROPERTY_ENABLE_SPLIT; + enableCompress = GETPROPERTY_ENABLE_COMPRESS; + + dataLimit = GETPROPERTY_DATA_LIMIT; + dataOffset = GETPROPERTY_DATA_OFFSET; + + cacheSlots = GETPROPERTY_CACHE_SLOTS; + cacheThreshold = GETPROPERTY_CACHE_THRESHOLD; + cacheLowerThreshold = GETPROPERTY_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~GetPropertyStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "GetProperty"; + } + + virtual unsigned char opcode() const + { + return X_GetProperty; + } + + virtual unsigned int storage() const + { + return sizeof(GetPropertyMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new GetPropertyMessage(); + } + + virtual Message *create(const Message &message) const + { + return new GetPropertyMessage((const GetPropertyMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (GetPropertyMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* GetProperty_H */ diff --git a/nxcomp/src/GetPropertyReply.cpp b/nxcomp/src/GetPropertyReply.cpp new file mode 100644 index 000000000..bf6879c5f --- /dev/null +++ b/nxcomp/src/GetPropertyReply.cpp @@ -0,0 +1,304 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "GetPropertyReply.h" + +#include "ServerCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +GetPropertyReplyStore::GetPropertyReplyStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = GETPROPERTYREPLY_ENABLE_CACHE; + enableData = GETPROPERTYREPLY_ENABLE_DATA; + enableSplit = GETPROPERTYREPLY_ENABLE_SPLIT; + + // Since ProtoStep7 (#issue 108) + enableCompress = GETPROPERTYREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = GETPROPERTYREPLY_DATA_LIMIT; + dataOffset = GETPROPERTYREPLY_DATA_OFFSET; + + cacheSlots = GETPROPERTYREPLY_CACHE_SLOTS; + cacheThreshold = GETPROPERTYREPLY_CACHE_THRESHOLD; + cacheLowerThreshold = GETPROPERTYREPLY_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +GetPropertyReplyStore::~GetPropertyReplyStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int GetPropertyReplyStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ServerCache *serverCache = (ServerCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message identity.\n" + << logofs_flush; + #endif + + unsigned char format = (unsigned int) *(buffer + 1); + + encodeBuffer.encodeCachedValue(format, 8, + serverCache -> getPropertyFormatCache); + + unsigned int numBytes = GetULONG(buffer + 16, bigEndian); + + encodeBuffer.encodeValue(numBytes, 32, 9); + + if (format == 16) + { + numBytes <<= 1; + } + else if (format == 32) + { + numBytes <<= 2; + } + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 8, bigEndian), 29, + serverCache -> getPropertyTypeCache, 9); + + encodeBuffer.encodeValue(GetULONG(buffer + 12, bigEndian), 32, 9); + + #ifdef DEBUG + *logofs << name() << ": Encoded full message identity.\n" + << logofs_flush; + #endif + + return 1; +} + +int GetPropertyReplyStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ServerCache *serverCache = (ServerCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message identity.\n" + << logofs_flush; + #endif + + unsigned char format; + + decodeBuffer.decodeCachedValue(format, 8, + serverCache -> getPropertyFormatCache); + + unsigned int length; + + decodeBuffer.decodeValue(length, 32, 9); + + unsigned int numBytes = length; + + if (format == 16) + { + numBytes <<= 1; + } + else if (format == 32) + { + numBytes <<= 2; + } + + size = 32 + RoundUp4(numBytes); + + buffer = writeBuffer -> addMessage(size); + + *(buffer + 1) = format; + + PutULONG(length, buffer + 16, bigEndian); + + unsigned int value; + + decodeBuffer.decodeCachedValue(value, 29, + serverCache -> getPropertyTypeCache, 9); + + PutULONG(value, buffer + 8, bigEndian); + + decodeBuffer.decodeValue(value, 32, 9); + + PutULONG(value, buffer + 12, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Decoded full message identity.\n" + << logofs_flush; + #endif + + return 1; +} + +int GetPropertyReplyStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GetPropertyReplyMessage *getPropertyReply = (GetPropertyReplyMessage *) message; + + getPropertyReply -> format = *(buffer + 1); + + getPropertyReply -> type = GetULONG(buffer + 8, bigEndian); + getPropertyReply -> after = GetULONG(buffer + 12, bigEndian); + getPropertyReply -> items = GetULONG(buffer + 16, bigEndian); + + // + // Cleanup the padding bytes. + // + + unsigned int uiLengthInBytes; + unsigned int uiFormat; + + if ((int) size > GETPROPERTYREPLY_DATA_OFFSET) + { + uiLengthInBytes = getPropertyReply -> items; + + uiFormat = *(buffer + 1); + + #ifdef DEBUG + *logofs << name() << ": length " << uiLengthInBytes + << ", format " << uiFormat << ", size " + << size << ".\n" << logofs_flush; + #endif + + if (uiFormat == 16) + { + uiLengthInBytes <<= 1; + } + else if (uiFormat == 32) + { + uiLengthInBytes <<= 2; + } + + unsigned char *end = ((unsigned char *) buffer) + size; + unsigned char *pad = ((unsigned char *) buffer) + GETPROPERTYREPLY_DATA_OFFSET + uiLengthInBytes; + + CleanData((unsigned char *) pad, end - pad); + } + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int GetPropertyReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + GetPropertyReplyMessage *getPropertyReply = (GetPropertyReplyMessage *) message; + + *(buffer + 1) = getPropertyReply -> format; + + PutULONG(getPropertyReply -> type, buffer + 8, bigEndian); + PutULONG(getPropertyReply -> after, buffer + 12, bigEndian); + PutULONG(getPropertyReply -> items, buffer + 16, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void GetPropertyReplyStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + GetPropertyReplyMessage *getPropertyReply = (GetPropertyReplyMessage *) message; + + *logofs << name() << ": Identity format " + << (unsigned) getPropertyReply -> format << ", type " + << getPropertyReply -> type << ", after " << getPropertyReply -> after + << ", items " << getPropertyReply -> items << ", size " + << getPropertyReply -> size_ << ".\n"; + + #endif +} + +void GetPropertyReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Fields format, type, after, items. + // + + md5_append(md5_state_, buffer + 1, 1); + md5_append(md5_state_, buffer + 8, 12); +} + +void GetPropertyReplyStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ +} + +void GetPropertyReplyStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ +} diff --git a/nxcomp/src/GetPropertyReply.h b/nxcomp/src/GetPropertyReply.h new file mode 100644 index 000000000..01634b408 --- /dev/null +++ b/nxcomp/src/GetPropertyReply.h @@ -0,0 +1,160 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef GetPropertyReply_H +#define GetPropertyReply_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define GETPROPERTYREPLY_ENABLE_CACHE 1 +#define GETPROPERTYREPLY_ENABLE_DATA 1 +#define GETPROPERTYREPLY_ENABLE_SPLIT 0 + +#define GETPROPERTYREPLY_DATA_LIMIT 1048576 - 32 +#define GETPROPERTYREPLY_DATA_OFFSET 32 + +#define GETPROPERTYREPLY_CACHE_SLOTS 400 +#define GETPROPERTYREPLY_CACHE_THRESHOLD 5 +#define GETPROPERTYREPLY_CACHE_LOWER_THRESHOLD 1 + +#define GETPROPERTYREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +// +// The message class. +// + +class GetPropertyReplyMessage : public Message +{ + friend class GetPropertyReplyStore; + + public: + + GetPropertyReplyMessage() + { + } + + ~GetPropertyReplyMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char format; + unsigned int type; + unsigned int after; + unsigned int items; +}; + +class GetPropertyReplyStore : public MessageStore +{ + public: + + GetPropertyReplyStore(StaticCompressor *compressor); + + virtual ~GetPropertyReplyStore(); + + virtual const char *name() const + { + return "GetPropertyReply"; + } + + virtual unsigned char opcode() const + { + return X_GetProperty; + } + + virtual unsigned int storage() const + { + return sizeof(GetPropertyReplyMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new GetPropertyReplyMessage(); + } + + virtual Message *create(const Message &message) const + { + return new GetPropertyReplyMessage((const GetPropertyReplyMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (GetPropertyReplyMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* GetPropertyReply_H */ diff --git a/nxcomp/src/ImageText16.cpp b/nxcomp/src/ImageText16.cpp new file mode 100644 index 000000000..af057635f --- /dev/null +++ b/nxcomp/src/ImageText16.cpp @@ -0,0 +1,231 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ImageText16.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int ImageText16Store::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ImageText16Message *imageText16 = (ImageText16Message *) message; + + // + // Here is the fingerprint. + // + + imageText16 -> len = *(buffer + 1); + + imageText16 -> drawable = GetULONG(buffer + 4, bigEndian); + imageText16 -> gcontext = GetULONG(buffer + 8, bigEndian); + + imageText16 -> x = GetUINT(buffer + 12, bigEndian); + imageText16 -> y = GetUINT(buffer + 14, bigEndian); + + if ((int) size > dataOffset) + { + int pad = (size - dataOffset) - (imageText16 -> len * 2); + + if (pad > 0) + { + CleanData((unsigned char *) buffer + size - pad, pad); + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int ImageText16Store::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ImageText16Message *imageText16 = (ImageText16Message *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = imageText16 -> len; + + PutULONG(imageText16 -> drawable, buffer + 4, bigEndian); + PutULONG(imageText16 -> gcontext, buffer + 8, bigEndian); + + PutUINT(imageText16 -> x, buffer + 12, bigEndian); + PutUINT(imageText16 -> y, buffer + 14, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void ImageText16Store::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + ImageText16Message *imageText16 = (ImageText16Message *) message; + + *logofs << name() << ": Identity len " << (unsigned int) imageText16 -> len + << " drawable " << imageText16 -> drawable << ", gcontext " + << imageText16 -> gcontext << ", x " << imageText16 -> x << ", y " + << imageText16 -> y << ", size " << imageText16 -> size_ << ".\n"; + + #endif +} + +void ImageText16Store::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 1, 1); +} + +void ImageText16Store::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + ImageText16Message *imageText16 = (ImageText16Message *) message; + ImageText16Message *cachedImageText16 = (ImageText16Message *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << imageText16 -> drawable + << " as " << "drawable" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(imageText16 -> drawable, clientCache -> drawableCache); + + cachedImageText16 -> drawable = imageText16 -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << imageText16 -> gcontext + << " as " << "gcontext" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(imageText16 -> gcontext, clientCache -> gcCache); + + cachedImageText16 -> gcontext = imageText16 -> gcontext; + + #ifdef TEST + *logofs << name() << ": Encoding value " << imageText16 -> x + << " as " << "x" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_x = imageText16 -> x - cachedImageText16 -> x; + + encodeBuffer.encodeCachedValue(diff_x, 16, + clientCache -> imageTextCacheX); + + cachedImageText16 -> x = imageText16 -> x; + + #ifdef TEST + *logofs << name() << ": Encoding value " << imageText16 -> y + << " as " << "y" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_y = imageText16 -> y - cachedImageText16 -> y; + + encodeBuffer.encodeCachedValue(diff_y, 16, + clientCache -> imageTextCacheY); + + cachedImageText16 -> y = imageText16 -> y; +} + +void ImageText16Store::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + ImageText16Message *imageText16 = (ImageText16Message *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + imageText16 -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << imageText16 -> drawable + << " as " << "drawable" << " field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + imageText16 -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << imageText16 -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> imageTextCacheX); + + imageText16 -> x += value; + imageText16 -> x &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << imageText16 -> x + << " as x field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> imageTextCacheY); + + imageText16 -> y += value; + imageText16 -> y &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << imageText16 -> y + << " as y field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/ImageText16.h b/nxcomp/src/ImageText16.h new file mode 100644 index 000000000..98462ab35 --- /dev/null +++ b/nxcomp/src/ImageText16.h @@ -0,0 +1,190 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ImageText16_H +#define ImageText16_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define IMAGETEXT16_ENABLE_CACHE 1 +#define IMAGETEXT16_ENABLE_DATA 0 +#define IMAGETEXT16_ENABLE_SPLIT 0 +#define IMAGETEXT16_ENABLE_COMPRESS 0 + +#define IMAGETEXT16_DATA_LIMIT 512 +#define IMAGETEXT16_DATA_OFFSET 16 + +#define IMAGETEXT16_CACHE_SLOTS 3000 +#define IMAGETEXT16_CACHE_THRESHOLD 5 +#define IMAGETEXT16_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class ImageText16Message : public Message +{ + friend class ImageText16Store; + + public: + + ImageText16Message() + { + } + + ~ImageText16Message() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char len; + + unsigned int drawable; + unsigned int gcontext; + + unsigned short x; + unsigned short y; +}; + +class ImageText16Store : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + ImageText16Store() : MessageStore() + { + enableCache = IMAGETEXT16_ENABLE_CACHE; + enableData = IMAGETEXT16_ENABLE_DATA; + enableSplit = IMAGETEXT16_ENABLE_SPLIT; + enableCompress = IMAGETEXT16_ENABLE_COMPRESS; + + dataLimit = IMAGETEXT16_DATA_LIMIT; + dataOffset = IMAGETEXT16_DATA_OFFSET; + + cacheSlots = IMAGETEXT16_CACHE_SLOTS; + cacheThreshold = IMAGETEXT16_CACHE_THRESHOLD; + cacheLowerThreshold = IMAGETEXT16_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~ImageText16Store() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "ImageText16"; + } + + virtual unsigned char opcode() const + { + return X_ImageText16; + } + + virtual unsigned int storage() const + { + return sizeof(ImageText16Message); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new ImageText16Message(); + } + + virtual Message *create(const Message &message) const + { + return new ImageText16Message((const ImageText16Message &) message); + } + + virtual void destroy(Message *message) const + { + delete (ImageText16Message *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* ImageText16_H */ diff --git a/nxcomp/src/ImageText8.cpp b/nxcomp/src/ImageText8.cpp new file mode 100644 index 000000000..61fcef825 --- /dev/null +++ b/nxcomp/src/ImageText8.cpp @@ -0,0 +1,231 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ImageText8.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int ImageText8Store::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ImageText8Message *imageText8 = (ImageText8Message *) message; + + // + // Here is the fingerprint. + // + + imageText8 -> len = *(buffer + 1); + + imageText8 -> drawable = GetULONG(buffer + 4, bigEndian); + imageText8 -> gcontext = GetULONG(buffer + 8, bigEndian); + + imageText8 -> x = GetUINT(buffer + 12, bigEndian); + imageText8 -> y = GetUINT(buffer + 14, bigEndian); + + if ((int) size > dataOffset) + { + int pad = (size - dataOffset) - imageText8 -> len; + + if (pad > 0) + { + CleanData((unsigned char *) buffer + size - pad, pad); + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int ImageText8Store::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ImageText8Message *imageText8 = (ImageText8Message *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = imageText8 -> len; + + PutULONG(imageText8 -> drawable, buffer + 4, bigEndian); + PutULONG(imageText8 -> gcontext, buffer + 8, bigEndian); + + PutUINT(imageText8 -> x, buffer + 12, bigEndian); + PutUINT(imageText8 -> y, buffer + 14, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void ImageText8Store::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + ImageText8Message *imageText8 = (ImageText8Message *) message; + + *logofs << name() << ": Identity len " << (unsigned int) imageText8 -> len + << " drawable " << imageText8 -> drawable << ", gcontext " + << imageText8 -> gcontext << ", x " << imageText8 -> x << ", y " + << imageText8 -> y << ", size " << imageText8 -> size_ << ".\n"; + + #endif +} + +void ImageText8Store::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 1, 1); +} + +void ImageText8Store::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + ImageText8Message *imageText8 = (ImageText8Message *) message; + ImageText8Message *cachedImageText8 = (ImageText8Message *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << imageText8 -> drawable + << " as " << "drawable" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(imageText8 -> drawable, clientCache -> drawableCache); + + cachedImageText8 -> drawable = imageText8 -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << imageText8 -> gcontext + << " as " << "gcontext" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(imageText8 -> gcontext, clientCache -> gcCache); + + cachedImageText8 -> gcontext = imageText8 -> gcontext; + + #ifdef TEST + *logofs << name() << ": Encoding value " << imageText8 -> x + << " as " << "x" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_x = imageText8 -> x - cachedImageText8 -> x; + + encodeBuffer.encodeCachedValue(diff_x, 16, + clientCache -> imageTextCacheX); + + cachedImageText8 -> x = imageText8 -> x; + + #ifdef TEST + *logofs << name() << ": Encoding value " << imageText8 -> y + << " as " << "y" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_y = imageText8 -> y - cachedImageText8 -> y; + + encodeBuffer.encodeCachedValue(diff_y, 16, + clientCache -> imageTextCacheY); + + cachedImageText8 -> y = imageText8 -> y; +} + +void ImageText8Store::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + ImageText8Message *imageText8 = (ImageText8Message *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + imageText8 -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << imageText8 -> drawable + << " as " << "drawable" << " field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + imageText8 -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << imageText8 -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> imageTextCacheX); + + imageText8 -> x += value; + imageText8 -> x &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << imageText8 -> x + << " as x field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> imageTextCacheY); + + imageText8 -> y += value; + imageText8 -> y &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << imageText8 -> y + << " as y field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/ImageText8.h b/nxcomp/src/ImageText8.h new file mode 100644 index 000000000..aa9ccb5d9 --- /dev/null +++ b/nxcomp/src/ImageText8.h @@ -0,0 +1,190 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ImageText8_H +#define ImageText8_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define IMAGETEXT8_ENABLE_CACHE 1 +#define IMAGETEXT8_ENABLE_DATA 0 +#define IMAGETEXT8_ENABLE_SPLIT 0 +#define IMAGETEXT8_ENABLE_COMPRESS 0 + +#define IMAGETEXT8_DATA_LIMIT 256 +#define IMAGETEXT8_DATA_OFFSET 16 + +#define IMAGETEXT8_CACHE_SLOTS 3000 +#define IMAGETEXT8_CACHE_THRESHOLD 5 +#define IMAGETEXT8_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class ImageText8Message : public Message +{ + friend class ImageText8Store; + + public: + + ImageText8Message() + { + } + + ~ImageText8Message() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char len; + + unsigned int drawable; + unsigned int gcontext; + + unsigned short x; + unsigned short y; +}; + +class ImageText8Store : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + ImageText8Store() : MessageStore() + { + enableCache = IMAGETEXT8_ENABLE_CACHE; + enableData = IMAGETEXT8_ENABLE_DATA; + enableSplit = IMAGETEXT8_ENABLE_SPLIT; + enableCompress = IMAGETEXT8_ENABLE_COMPRESS; + + dataLimit = IMAGETEXT8_DATA_LIMIT; + dataOffset = IMAGETEXT8_DATA_OFFSET; + + cacheSlots = IMAGETEXT8_CACHE_SLOTS; + cacheThreshold = IMAGETEXT8_CACHE_THRESHOLD; + cacheLowerThreshold = IMAGETEXT8_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~ImageText8Store() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "ImageText8"; + } + + virtual unsigned char opcode() const + { + return X_ImageText8; + } + + virtual unsigned int storage() const + { + return sizeof(ImageText8Message); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new ImageText8Message(); + } + + virtual Message *create(const Message &message) const + { + return new ImageText8Message((const ImageText8Message &) message); + } + + virtual void destroy(Message *message) const + { + delete (ImageText8Message *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* ImageText8_H */ diff --git a/nxcomp/src/IntCache.cpp b/nxcomp/src/IntCache.cpp new file mode 100644 index 000000000..c72b81200 --- /dev/null +++ b/nxcomp/src/IntCache.cpp @@ -0,0 +1,230 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "Misc.h" +#include "IntCache.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +IntCache::IntCache(unsigned int size) + + : size_(size), length_(0), buffer_(new unsigned int[size]), + lastDiff_(0), lastValueInserted_(0), predictedBlockSize_(0) +{ +} + +int IntCache::lookup(unsigned int &value, unsigned int &index, + unsigned int mask, unsigned int &sameDiff) +{ + for (unsigned int i = 0; i < length_; i++) + { + if (value == buffer_[i]) + { + index = i; + if (i) + { + unsigned int target = (i >> 1); + do + { + buffer_[i] = buffer_[i - 1]; + i--; + } + while (i > target); + buffer_[target] = value; + } + return 1; + } + } + unsigned int insertionPoint; + if (2 >= length_) + insertionPoint = length_; + else + insertionPoint = 2; + unsigned int start; + if (length_ >= size_) + start = size_ - 1; + else + { + start = length_; + length_++; + } + for (unsigned int k = start; k > insertionPoint; k--) + buffer_[k] = buffer_[k - 1]; + buffer_[insertionPoint] = value; + unsigned int diff = value - lastValueInserted_; + + lastValueInserted_ = (value & mask); + value = (diff & mask); + sameDiff = (value == lastDiff_); + if (!sameDiff) + { + lastDiff_ = value; + + unsigned int lastChangeIndex = 0; + unsigned int lastBitIsOne = (lastDiff_ & 0x1); + unsigned int j = 1; + for (unsigned int nextMask = 0x2; nextMask & mask; nextMask <<= 1) + { + unsigned int nextBitIsOne = (lastDiff_ & nextMask); + if (nextBitIsOne) + { + if (!lastBitIsOne) + { + lastChangeIndex = j; + lastBitIsOne = nextBitIsOne; + } + } + else + { + if (lastBitIsOne) + { + lastChangeIndex = j; + lastBitIsOne = nextBitIsOne; + } + } + j++; + } + predictedBlockSize_ = lastChangeIndex + 1; + if (predictedBlockSize_ < 2) + predictedBlockSize_ = 2; + } + return 0; +} + +void IntCache::insert(unsigned int &value, unsigned int mask) +{ + unsigned int insertionPoint; + if (2 >= length_) + insertionPoint = length_; + else + insertionPoint = 2; + unsigned int start; + if (length_ >= size_) + start = size_ - 1; + else + { + start = length_; + length_++; + } + for (unsigned int k = start; k > insertionPoint; k--) + buffer_[k] = buffer_[k - 1]; + if (lastDiff_ != value) + { + lastDiff_ = value; + unsigned int lastChangeIndex = 0; + unsigned int lastBitIsOne = (lastDiff_ & 0x1); + unsigned int j = 1; + for (unsigned int nextMask = 0x2; nextMask & mask; nextMask <<= 1) + { + unsigned int nextBitIsOne = (lastDiff_ & nextMask); + if (nextBitIsOne) + { + if (!lastBitIsOne) + { + lastChangeIndex = j; + lastBitIsOne = nextBitIsOne; + } + } + else + { + if (lastBitIsOne) + { + lastChangeIndex = j; + lastBitIsOne = nextBitIsOne; + } + } + j++; + } + predictedBlockSize_ = lastChangeIndex + 1; + if (predictedBlockSize_ < 2) + predictedBlockSize_ = 2; + } + lastValueInserted_ += value; + lastValueInserted_ &= mask; + buffer_[insertionPoint] = lastValueInserted_; + value = lastValueInserted_; +} + +void IntCache::push(unsigned int &value, unsigned int mask) +{ + // + // Using a memmove() appears to be slower. + // + // memmove((char *) &buffer_[1], (char *) &buffer_[0], + // sizeof(unsigned int) * (size_ - 1)); + // + // if (length_ < size_) + // { + // length_++; + // } + // + + unsigned int start; + + if (length_ >= size_) + { + start = size_ - 1; + } + else + { + start = length_; + + length_++; + } + + for (unsigned int k = start; k > 0; k--) + { + buffer_[k] = buffer_[k - 1]; + } + + value &= mask; + + buffer_[0] = value; +} + +void IntCache::dump() +{ + #ifdef DUMP + + *logofs << "IntCache: Dumping content of cache at " + << (void *) this << ":\n" << logofs_flush; + + for (unsigned int i = 0; i < length_; i++) + { + *logofs << "IntCache: [" << i << "][" << buffer_[i] << "]\n"; + } + + #endif +} diff --git a/nxcomp/src/IntCache.h b/nxcomp/src/IntCache.h new file mode 100644 index 000000000..69c522325 --- /dev/null +++ b/nxcomp/src/IntCache.h @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef IntCache_H +#define IntCache_H + +class IntCache +{ + public: + + IntCache(unsigned int size); + + ~IntCache() + { + delete [] buffer_; + } + + unsigned int getSize() const + { + return length_; + } + + int lookup(unsigned int &value, unsigned int &index, + unsigned int mask, unsigned int &sameDiff); + + // + // This can be inlined as it is only + // called by decodeCachedValue(). + // + + unsigned int get(unsigned int index) + { + unsigned int result = buffer_[index]; + + if (index != 0) + { + // + // Using a memmove() appears to be slower. + // + // unsigned int target = index >> 1; + // + // memmove((char *) &buffer_[target + 1], (char *) &buffer_[target], + // sizeof(unsigned int) * (index - target)); + // + // buffer_[target] = result; + // + + unsigned int i = index; + + unsigned int target = (i >> 1); + + do + { + buffer_[i] = buffer_[i - 1]; + + i--; + } + while (i > target); + + buffer_[target] = result; + } + + return result; + } + + void insert(unsigned int &value, unsigned int mask); + + void push(unsigned int &value, unsigned int mask); + + void dump(); + + unsigned int getLastDiff(unsigned int mask) const + { + return lastDiff_; + } + + unsigned int getBlockSize(unsigned int bits) const + { + if (bits > 0) + { + return (predictedBlockSize_ < bits ? predictedBlockSize_ : bits); + } + + return predictedBlockSize_; + } + + private: + + unsigned int size_; + unsigned int length_; + unsigned int *buffer_; + unsigned int lastDiff_; + unsigned int lastValueInserted_; + unsigned int predictedBlockSize_; +}; + +#endif /* IntCache_H */ diff --git a/nxcomp/src/InternAtom.cpp b/nxcomp/src/InternAtom.cpp new file mode 100644 index 000000000..9d0ab1b6d --- /dev/null +++ b/nxcomp/src/InternAtom.cpp @@ -0,0 +1,131 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "InternAtom.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int InternAtomStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + InternAtomMessage *internAtom = (InternAtomMessage *) message; + + // + // Here is the fingerprint. + // + + internAtom -> only_if_exists = *(buffer + 1); + internAtom -> name_length = GetUINT(buffer + 4, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + // + // Clean up padding bytes. + // + + if ((int) size > dataOffset) + { + unsigned char *end = ((unsigned char *) buffer) + size; + + for (unsigned char *pad = ((unsigned char *) buffer) + 8 + + internAtom -> name_length; pad < end; pad++) + { + *pad = 0; + } + } + + return 1; +} + +int InternAtomStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + InternAtomMessage *internAtom = (InternAtomMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = internAtom -> only_if_exists; + + PutUINT(internAtom -> name_length, buffer + 4, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void InternAtomStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + InternAtomMessage *internAtom = (InternAtomMessage *) message; + + *logofs << name() << ": Identity only_if_exists " + << (unsigned int) internAtom -> only_if_exists + << ", name_length " << internAtom -> name_length + << ", name '"; + + for (int i = 0; i < internAtom -> name_length; i++) + { + *logofs << internAtom -> data_[i]; + } + + *logofs << "'.\n" << logofs_flush; + + #endif +} + +void InternAtomStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 1, 1); + md5_append(md5_state_, buffer + 4, 2); +} diff --git a/nxcomp/src/InternAtom.h b/nxcomp/src/InternAtom.h new file mode 100644 index 000000000..6e69eca24 --- /dev/null +++ b/nxcomp/src/InternAtom.h @@ -0,0 +1,178 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef InternAtom_H +#define InternAtom_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define INTERNATOM_ENABLE_CACHE 1 +#define INTERNATOM_ENABLE_DATA 0 +#define INTERNATOM_ENABLE_SPLIT 0 +#define INTERNATOM_ENABLE_COMPRESS 0 + +#define INTERNATOM_DATA_LIMIT 80 +#define INTERNATOM_DATA_OFFSET 8 + +#define INTERNATOM_CACHE_SLOTS 2000 +#define INTERNATOM_CACHE_THRESHOLD 2 +#define INTERNATOM_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class InternAtomMessage : public Message +{ + friend class InternAtomStore; + + public: + + InternAtomMessage() + { + } + + ~InternAtomMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char only_if_exists; + unsigned short name_length; +}; + +class InternAtomStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + InternAtomStore() : MessageStore() + { + enableCache = INTERNATOM_ENABLE_CACHE; + enableData = INTERNATOM_ENABLE_DATA; + enableSplit = INTERNATOM_ENABLE_SPLIT; + enableCompress = INTERNATOM_ENABLE_COMPRESS; + + dataLimit = INTERNATOM_DATA_LIMIT; + dataOffset = INTERNATOM_DATA_OFFSET; + + cacheSlots = INTERNATOM_CACHE_SLOTS; + cacheThreshold = INTERNATOM_CACHE_THRESHOLD; + cacheLowerThreshold = INTERNATOM_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~InternAtomStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "InternAtom"; + } + + virtual unsigned char opcode() const + { + return X_InternAtom; + } + + virtual unsigned int storage() const + { + return sizeof(InternAtomMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new InternAtomMessage(); + } + + virtual Message *create(const Message &message) const + { + return new InternAtomMessage((const InternAtomMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (InternAtomMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* InternAtom_H */ diff --git a/nxcomp/src/Jpeg.cpp b/nxcomp/src/Jpeg.cpp new file mode 100644 index 000000000..64a537497 --- /dev/null +++ b/nxcomp/src/Jpeg.cpp @@ -0,0 +1,890 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef ANDROID +#include +#endif +#include +#include +#include + +#ifdef __cplusplus + +extern "C" +{ + #include + #include +} + +#else + +#include +#include + +#endif + +#include "Misc.h" +#include "Jpeg.h" +#include "Unpack.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define RGB24_TO_PIXEL(bpp,r,g,b) \ + ((((CARD##bpp)(r) & 0xff) * srcRedMax + 127) / 255 \ + << srcRedShift | \ + (((CARD##bpp)(g) & 0xff) * srcGreenMax + 127) / 255 \ + << srcGreenShift | \ + (((CARD##bpp)(b) & 0xff) * srcBlueMax + 127) / 255 \ + << srcBlueShift) + +#define RGB24_TO_PIXEL32(r,g,b) \ + (((CARD32)(r) & 0xff) << srcRedShift | \ + ((CARD32)(g) & 0xff) << srcGreenShift | \ + ((CARD32)(b) & 0xff) << srcBlueShift) + +// +// Functions from Unpack.cpp +// + +extern int Unpack32To32(const T_colormask *colormask, const unsigned int *data, + unsigned int *out, unsigned int *end); + +extern int Unpack24To24(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +extern int Unpack16To16(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +// +// Local functions used for the jpeg decompression. +// + +static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData, int compressedLen); +static void JpegInitSource(j_decompress_ptr cinfo); +static void JpegTermSource(j_decompress_ptr cinfo); +static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes); + +static boolean JpegFillInputBuffer(j_decompress_ptr cinfo); + +static int DecompressJpeg16(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder); + +static int DecompressJpeg24(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder); + +static int DecompressJpeg32(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder); + +void UnpackJpegErrorHandler(j_common_ptr cinfo); + +// +// Colormap stuff. +// + +CARD16 srcRedMax, srcGreenMax, srcBlueMax; +CARD8 srcRedShift, srcGreenShift, srcBlueShift; + +// +// Error handler. +// + +static bool jpegError; + +jmp_buf UnpackJpegContext; + +void UnpackJpegErrorHandler(j_common_ptr cinfo) +{ + #ifdef PANIC + *logofs << "UnpackJpegErrorHandler: PANIC! Detected error in JPEG decompression.\n" + << logofs_flush; + + *logofs << "UnpackJpegErrorHandler: PANIC! Trying to revert to the previous context.\n" + << logofs_flush; + #endif + + jpegError = 1; + + longjmp(UnpackJpegContext, 1); +} + +// +// Attributes used for the jpeg decompression. +// + +static struct jpeg_source_mgr jpegSrcManager; +static JOCTET *jpegBufferPtr; +static size_t jpegBufferLen; + +static char *tmpBuf; +static int tmpBufSize = 0; + +int UnpackJpeg(T_geometry *geometry, unsigned char method, unsigned char *srcData, + int srcSize, int dstBpp, int dstWidth, int dstHeight, + unsigned char *dstData, int dstSize) +{ + int byteOrder = geometry -> image_byte_order; + + // + // Check if data is coming from a failed unsplit. + // + + if (srcSize < 2 || (srcData[0] == SPLIT_PATTERN && + srcData[1] == SPLIT_PATTERN)) + { + #ifdef WARNING + *logofs << "UnpackJpeg: WARNING! Skipping unpack of dummy data.\n" + << logofs_flush; + #endif + + return -1; + } + + #ifdef DEBUG + *logofs << "UnpackJpeg: Decompression. Source size " + << srcSize << " bits per plane " << dstBpp + << ".\n" << logofs_flush; + #endif + + srcRedShift = ffs(geometry -> red_mask) - 1; + srcGreenShift = ffs(geometry -> green_mask) - 1; + srcBlueShift = ffs(geometry -> blue_mask) - 1; + + #ifdef DEBUG + *logofs << "UnpackJpeg: Red shift " << (int) srcRedShift + << " green shift " << (int) srcGreenShift << " blue shift " + << (int) srcBlueShift << ".\n" << logofs_flush; + #endif + + srcRedMax = geometry -> red_mask >> srcRedShift; + srcGreenMax = geometry -> green_mask >> srcGreenShift; + srcBlueMax = geometry -> blue_mask >> srcBlueShift; + + #ifdef DEBUG + *logofs << "UnpackJpeg: Red mask " << (void *) geometry -> red_mask + << " green mask " << (void *) geometry -> green_mask + << " blue mask " << (void *) geometry -> blue_mask + << ".\n" << logofs_flush; + #endif + + #ifdef DEBUG + *logofs << "UnpackJpeg: Red max " << srcRedMax << " green max " + << srcGreenMax << " blue max " << srcBlueMax + << ".\n" << logofs_flush; + #endif + + // + // Make enough space in the temporary + // buffer to have one complete row of + // the image with 3 bytes for a pixel. + // + + tmpBufSize = dstWidth * 3; + tmpBuf = new char[tmpBufSize]; + + if (tmpBuf == NULL) + { + #ifdef PANIC + *logofs << "UnpackJpeg: PANIC! Cannot allocate " + << dstWidth * 3 << " bytes for Jpeg " + << "decompressed data.\n" << logofs_flush; + #endif + + delete [] tmpBuf; + + return -1; + } + + int result = 1; + + switch(dstBpp) + { + case 8: + { + // + // Simply move the data from srcData to dstData + // taking into consideration the correct padding. + // + + int row; + + unsigned char * dstBuff = dstData; + unsigned char * srcBuff = srcData; + + for (row = 0; row < dstHeight; row++) + { + memcpy(dstBuff, srcBuff, dstWidth); + + dstBuff += RoundUp4(dstWidth); + srcBuff += dstWidth; + } + + break; + } + case 16: + { + result = DecompressJpeg16(srcData, srcSize, dstWidth, + dstHeight, dstData, byteOrder); + break; + } + case 24: + { + result = DecompressJpeg24(srcData, srcSize, dstWidth, + dstHeight, dstData, byteOrder); + break; + } + case 32: + { + result = DecompressJpeg32(srcData, srcSize, dstWidth, + dstHeight, dstData, byteOrder); + break; + } + default: + { + #ifdef PANIC + *logofs << "UnpackJpeg: PANIC! Failed to decode Jpeg image. " + << " Unsupported Bpp value " << dstBpp + << " for the Jpeg compression" + << ".\n" << logofs_flush; + #endif + + delete [] tmpBuf; + + result = -1; + } + } + + #ifdef DEBUG + *logofs << "UnpackJpeg: Decompression finished with result " + << result << ".\n" << logofs_flush; + #endif + + if (result == -1) + { + delete [] tmpBuf; + + #ifdef PANIC + *logofs << "UnpackJpeg: PANIC! Failed to decode Jpeg image using " + << dstBpp << " Bpp destination.\n" << logofs_flush; + #endif + + return result; + } + + // + // Apply the correction for the brightness. + // + + int maskMethod; + + switch(method) + { + case PACK_JPEG_8_COLORS: + { + maskMethod = MASK_8_COLORS; + + break; + } + case PACK_JPEG_64_COLORS: + { + maskMethod = MASK_64_COLORS; + + break; + } + case PACK_JPEG_256_COLORS: + { + maskMethod = MASK_256_COLORS; + + break; + } + case PACK_JPEG_512_COLORS: + { + maskMethod = MASK_512_COLORS; + + break; + } + case PACK_JPEG_4K_COLORS: + { + maskMethod = MASK_4K_COLORS; + + break; + } + case PACK_JPEG_32K_COLORS: + { + maskMethod = MASK_32K_COLORS; + + break; + } + case PACK_JPEG_64K_COLORS: + { + maskMethod = MASK_64K_COLORS; + + break; + } + case PACK_JPEG_256K_COLORS: + { + maskMethod = MASK_256K_COLORS; + + break; + } + case PACK_JPEG_2M_COLORS: + { + maskMethod = MASK_2M_COLORS; + + break; + } + case PACK_JPEG_16M_COLORS: + { + maskMethod = MASK_16M_COLORS; + + break; + } + default: + { + delete [] tmpBuf; + + return -1; + } + } + + const T_colormask *colorMask = MethodColorMask(maskMethod); + + unsigned char *dstBuff = dstData; + + switch (dstBpp) + { + case 16: + { + Unpack16To16(colorMask, dstBuff, dstBuff, dstBuff + dstSize); + + break; + } + case 24: + { + break; + } + case 32: + { + Unpack32To32(colorMask, (unsigned int *) dstBuff, (unsigned int *) dstBuff, + (unsigned int *) (dstBuff + dstSize)); + break; + } + default: + { + delete [] tmpBuf; + + return -1; + } + } + + delete [] tmpBuf; + + return 1; +} + +// +// Functions that actually do the Jpeg decompression. +// + +int DecompressJpeg16(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + unsigned char *data; + JSAMPROW rowPointer[1]; + + unsigned int dx = 0; + unsigned int dy = 0; + + #ifdef DEBUG + *logofs << "DecompressJpeg16: Decompressing with length " + << compressedLen << " width " << w << " height " + << h << ".\n" << logofs_flush; + #endif + + jpegError = 0; + + cinfo.err = jpeg_std_error(&jerr); + + jerr.error_exit = UnpackJpegErrorHandler; + + if (setjmp(UnpackJpegContext) == 1) + { + #ifdef TEST + *logofs << "DecompressJpeg16: Out of the long jump with error '" + << jpegError << "'.\n" << logofs_flush; + #endif + + goto AbortDecompressJpeg16; + } + + jpeg_create_decompress(&cinfo); + + if (jpegError) goto AbortDecompressJpeg16; + + JpegSetSrcManager(&cinfo, compressedData, compressedLen); + + jpeg_read_header(&cinfo, TRUE); + + if (jpegError) goto AbortDecompressJpeg16; + + cinfo.out_color_space = JCS_RGB; + + jpeg_start_decompress(&cinfo); + + if (jpegError) goto AbortDecompressJpeg16; + + if (cinfo.output_width != w || + cinfo.output_height != h || + cinfo.output_components != 3) + { + #ifdef PANIC + *logofs << "DecompressJpeg16: PANIC! Wrong JPEG data received.\n" + << logofs_flush; + #endif + + jpeg_destroy_decompress(&cinfo); + + return -1; + } + + // + // PixelPtr points to dstBuf which is + // already padded correctly for the final + // image to put + // + + data = dstBuf; + + rowPointer[0] = (JSAMPROW) tmpBuf; + + unsigned long pixel; + + while (cinfo.output_scanline < cinfo.output_height) + { + jpeg_read_scanlines(&cinfo, rowPointer, 1); + + if (jpegError) goto AbortDecompressJpeg16; + + for (dx = 0; dx < w; dx++) + { + pixel = RGB24_TO_PIXEL(16, tmpBuf[dx * 3], tmpBuf[dx * 3 + 1], + tmpBuf[dx * 3 + 2]); + + // + // Follow the server byte order when arranging data. + // + + if (byteOrder == LSBFirst) + { + data[0] = (unsigned char) (pixel & 0xff); + data[1] = (unsigned char) ((pixel >> 8) & 0xff); + } + else + { + data[1] = (unsigned char) (pixel & 0xff); + data[0] = (unsigned char) ((pixel >> 8) & 0xff); + } + + data += 2; + } + + // + // Move data at the beginning of the + // next line. + // + + data = data + (RoundUp4(w * 2) - w * 2); + + dy++; + } + + AbortDecompressJpeg16: + + if (jpegError == 0) + { + jpeg_finish_decompress(&cinfo); + } + + jpeg_destroy_decompress(&cinfo); + + if (jpegError == 1) + { + #ifdef PANIC + *logofs << "DecompressJpeg16: Failed to decompress JPEG image.\n" + << logofs_flush; + #endif + + return -1; + } + + #ifdef TEST + *logofs << "DecompressJpeg16: Decompression finished with " + << dy << " lines handled.\n" << logofs_flush; + #endif + + return 1; +} + +int DecompressJpeg24(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + CARD8 *pixelPtr = NULL; + JSAMPROW rowPointer[1]; + + unsigned int dx = 0; + unsigned int dy = 0; + + #ifdef TEST + *logofs << "DecompressJpeg24: Decompressing with length " + << compressedLen << " width " << w << " height " + << h << ".\n" << logofs_flush; + #endif + + jpegError = 0; + + cinfo.err = jpeg_std_error(&jerr); + + jerr.error_exit = UnpackJpegErrorHandler; + + if (setjmp(UnpackJpegContext) == 1) + { + #ifdef TEST + *logofs << "DecompressJpeg24: Out of the long jump with error '" + << jpegError << "'.\n" << logofs_flush; + #endif + + goto AbortDecompressJpeg24; + } + + jpeg_create_decompress(&cinfo); + + if (jpegError) goto AbortDecompressJpeg24; + + JpegSetSrcManager(&cinfo, compressedData, compressedLen); + + jpeg_read_header(&cinfo, TRUE); + + if (jpegError) goto AbortDecompressJpeg24; + + cinfo.out_color_space = JCS_RGB; + + jpeg_start_decompress(&cinfo); + + if (jpegError) goto AbortDecompressJpeg24; + + if (cinfo.output_width != w || + cinfo.output_height != h || + cinfo.output_components != 3) + { + #ifdef PANIC + *logofs << "DecompressJpeg24: PANIC! Wrong JPEG data received.\n" + << logofs_flush; + #endif + + jpeg_destroy_decompress(&cinfo); + + return -1; + } + + // + // PixelPtr points to dstBuf which is + // already padded correctly for the final + // image to put. + // + + pixelPtr = (CARD8 *) dstBuf; + + rowPointer[0] = (JSAMPROW) tmpBuf; + + while (cinfo.output_scanline < cinfo.output_height) + { + jpeg_read_scanlines(&cinfo, rowPointer, 1); + + if (jpegError) goto AbortDecompressJpeg24; + + for (dx = 0; dx < w; dx++) + { + // + // Follow the server byte order when arranging data. + // + + if (byteOrder == LSBFirst) + { + pixelPtr[0] = tmpBuf[dx * 3]; + pixelPtr[1] = tmpBuf[dx * 3 + 1]; + pixelPtr[2] = tmpBuf[dx * 3 + 2]; + } + else + { + pixelPtr[2] = tmpBuf[dx * 3]; + pixelPtr[1] = tmpBuf[dx * 3 + 1]; + pixelPtr[0] = tmpBuf[dx * 3 + 2]; + } + + pixelPtr += 3; + } + + // + // Go to the next line. + // + + pixelPtr = (CARD8 *) (((char *) pixelPtr) + (RoundUp4(w * 3) - w * 3)); + + dy++; + } + + AbortDecompressJpeg24: + + if (jpegError == 0) + { + jpeg_finish_decompress(&cinfo); + } + + jpeg_destroy_decompress(&cinfo); + + if (jpegError == 1) + { + #ifdef PANIC + *logofs << "DecompressJpeg24: Failed to decompress JPEG image.\n" + << logofs_flush; + #endif + + return -1; + } + + #ifdef TEST + *logofs << "DecompressJpeg24: Decompression finished with " + << dy << " lines handled.\n" << logofs_flush; + #endif + + return 1; +} + +int DecompressJpeg32(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + unsigned char *data; + JSAMPROW rowPointer[1]; + + unsigned int dx = 0; + unsigned int dy = 0; + + #ifdef TEST + *logofs << "DecompressJpeg32: Decompressing with length " + << compressedLen << " width " << w << " height " + << h << ".\n" << logofs_flush; + #endif + + jpegError = 0; + + cinfo.err = jpeg_std_error(&jerr); + + jerr.error_exit = UnpackJpegErrorHandler; + + if (setjmp(UnpackJpegContext) == 1) + { + #ifdef TEST + *logofs << "DecompressJpeg32: Out of the long jump with error '" + << jpegError << "'.\n" << logofs_flush; + #endif + + goto AbortDecompressJpeg32; + } + + jpeg_create_decompress(&cinfo); + + if (jpegError) goto AbortDecompressJpeg32; + + JpegSetSrcManager(&cinfo, compressedData, compressedLen); + + jpeg_read_header(&cinfo, TRUE); + + if (jpegError) goto AbortDecompressJpeg32; + + cinfo.out_color_space = JCS_RGB; + + jpeg_start_decompress(&cinfo); + + if (jpegError) goto AbortDecompressJpeg32; + + if (cinfo.output_width != w || + cinfo.output_height != h || + cinfo.output_components != 3) + { + #ifdef PANIC + *logofs << "DecompressJpeg32 : PANIC! Wrong JPEG data received.\n" + << logofs_flush; + #endif + + jpeg_destroy_decompress(&cinfo); + + return -1; + } + + // + // PixelPtr points to dstBuf which is + // already padded correctly for the final + // image to put + // + + data = dstBuf; + + rowPointer[0] = (JSAMPROW) tmpBuf; + + unsigned long pixel; + + int i; + + while (cinfo.output_scanline < cinfo.output_height) + { + jpeg_read_scanlines(&cinfo, rowPointer, 1); + + if (jpegError) goto AbortDecompressJpeg32; + + for (dx = 0; dx < w; dx++) + { + pixel = RGB24_TO_PIXEL(32, tmpBuf[dx * 3], tmpBuf[dx * 3 + 1], + tmpBuf[dx * 3 + 2]); + + // + // Follow the server byte order when arranging data. + // + + if (byteOrder == LSBFirst) + { + for (i = 0; i < 4; i++) + { + data[i] = (unsigned char)(pixel & 0xff); + pixel >>= 8; + } + } + else + { + for (i = 3; i >= 0; i--) + { + data[i] = (unsigned char) (pixel & 0xff); + pixel >>= 8; + } + } + + data += 4; + } + + dy++; + } + + AbortDecompressJpeg32: + + if (jpegError == 0) + { + jpeg_finish_decompress(&cinfo); + } + + jpeg_destroy_decompress(&cinfo); + + if (jpegError == 1) + { + #ifdef PANIC + *logofs << "DecompressJpeg32: Failed to decompress JPEG image.\n" + << logofs_flush; + #endif + + return -1; + } + + #ifdef TEST + *logofs << "DecompressJpeg32: Decompression finished with " + << dy << " lines handled.\n" << logofs_flush; + #endif + + return 1; +} + +static void JpegInitSource(j_decompress_ptr cinfo) +{ + jpegError = 0; +} + +static boolean JpegFillInputBuffer(j_decompress_ptr cinfo) +{ + jpegError = 1; + + jpegSrcManager.bytes_in_buffer = jpegBufferLen; + jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr; + + return TRUE; +} + +static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes) +{ + if (num_bytes < 0 || (unsigned long) num_bytes > jpegSrcManager.bytes_in_buffer) + { + jpegError = 1; + + jpegSrcManager.bytes_in_buffer = jpegBufferLen; + jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr; + } + else + { + jpegSrcManager.next_input_byte += (size_t) num_bytes; + jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes; + } +} + +static void JpegTermSource(j_decompress_ptr cinfo) +{ +} + +static void JpegSetSrcManager(j_decompress_ptr cinfo, + CARD8 *compressedData, + int compressedLen) +{ + jpegBufferPtr = (JOCTET *) compressedData; + jpegBufferLen = (size_t) compressedLen; + + jpegSrcManager.init_source = JpegInitSource; + jpegSrcManager.fill_input_buffer = JpegFillInputBuffer; + jpegSrcManager.skip_input_data = JpegSkipInputData; + jpegSrcManager.resync_to_restart = jpeg_resync_to_restart; + jpegSrcManager.term_source = JpegTermSource; + jpegSrcManager.next_input_byte = jpegBufferPtr; + jpegSrcManager.bytes_in_buffer = jpegBufferLen; + + cinfo->src = &jpegSrcManager; +} diff --git a/nxcomp/src/Jpeg.h b/nxcomp/src/Jpeg.h new file mode 100644 index 000000000..58a5bffef --- /dev/null +++ b/nxcomp/src/Jpeg.h @@ -0,0 +1,36 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Jpeg_H +#define Jpeg_H + +#include "Misc.h" +#include "Unpack.h" + +int UnpackJpeg(T_geometry *geometry, unsigned char method, unsigned char *srcData, + int srcSize, int dstBpp, int dstWidth, int dstHeight, + unsigned char *dstData, int dstSize); + +#endif /* Jpeg_H */ diff --git a/nxcomp/src/Keeper.cpp b/nxcomp/src/Keeper.cpp new file mode 100644 index 000000000..4babbe8a6 --- /dev/null +++ b/nxcomp/src/Keeper.cpp @@ -0,0 +1,612 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "Keeper.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Remove the directory if it's empty +// since more than 30 * 24 h. +// + +#define EMPTY_DIR_TIME 2592000 + +// +// Sleep once any ONCE entries. +// + +#define ONCE 2 + +// +// Define this to trace messages while +// they are allocated and deallocated. +// + +#undef REFERENCES + +// +// This is used for reference count. +// + +#ifdef REFERENCES + +int File::references_ = 0; + +#endif + +bool T_older::operator () (File *a, File *b) const +{ + return a -> compare(b); +} + +File::File() +{ + name_ = NULL; + + size_ = 0; + time_ = 0; + + #ifdef REFERENCES + + references_++; + + *logofs << "Keeper: Created new File at " + << this << " out of " << references_ + << " allocated references.\n" + << logofs_flush; + + #endif +} + +// +// TODO: This class can leak industrial amounts of memory. +// I'm 100% sure that the desctructor is called and that +// also the string pointed in the File structure is dele- +// ted. Everything is logged, but still the memory is not +// freed. This is less a problem on Windows, where the me- +// mory occupation remains almost constant. Obviously the +// problem lies in the STL allocators of the GNU libstc++. +// + +File::~File() +{ + #ifdef TEST + *logofs << "Keeper: Deleting name for File at " + << this << ".\n" << logofs_flush; + #endif + + delete [] name_; + + #ifdef REFERENCES + + *logofs << "Keeper: Deleted File at " + << this << " out of " << references_ + << " allocated references.\n" + << logofs_flush; + + references_--; + + #endif +} + +bool File::compare(File *b) const +{ + if (this -> time_ == b -> time_) + { + return (this -> size_ < b -> size_); + } + + return (this -> time_ < b -> time_); +} + +Keeper::Keeper(int caches, int images, const char *root, + int sleep, int parent) +{ + caches_ = caches; + images_ = images; + sleep_ = sleep; + parent_ = parent; + + root_ = new char[strlen(root) + 1]; + + strcpy(root_, root); + + total_ = 0; + signal_ = 0; + + files_ = new T_files; +} + +Keeper::~Keeper() +{ + empty(); + + delete files_; + + delete [] root_; +} + +int Keeper::cleanupCaches() +{ + #ifdef TEST + *logofs << "Keeper: Looking for cache directories in '" + << root_ << "'.\n" << logofs_flush; + #endif + + DIR *rootDir = opendir(root_); + + if (rootDir != NULL) + { + dirent *dirEntry; + + struct stat fileStat; + + int baseSize = strlen(root_); + + int s = 0; + + while (((dirEntry = readdir(rootDir)) != NULL)) + { + if (s++ % ONCE == 0) usleep(sleep_ * 1000); + + if (signal_ != 0) break; + + if (strcmp(dirEntry -> d_name, "cache") == 0 || + strncmp(dirEntry -> d_name, "cache-", 6) == 0) + { + char *dirName = new char[baseSize + strlen(dirEntry -> d_name) + 2]; + + if (dirName == NULL) + { + #ifdef WARNING + *logofs << "Keeper: WARNING! Can't check directory entry '" + << dirEntry -> d_name << "'.\n" << logofs_flush; + #endif + + delete [] dirName; + + continue; + } + + strcpy(dirName, root_); + strcpy(dirName + baseSize, "/"); + strcpy(dirName + baseSize + 1, dirEntry -> d_name); + + #ifdef TEST + *logofs << "Keeper: Checking directory '" << dirName + << "'.\n" << logofs_flush; + #endif + + if (stat(dirName, &fileStat) == 0 && + S_ISDIR(fileStat.st_mode) != 0) + { + // + // Add to repository all the "C-" and + // "S-" files in the given directory. + // + + collect(dirName); + } + + delete [] dirName; + } + } + + closedir(rootDir); + } + else + { + #ifdef WARNING + *logofs << "Keeper: WARNING! Can't open NX root directory '" + << root_ << "'. Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Can't open NX root directory '" + << root_ << "'. Error is " << EGET() << " '" + << ESTR() << "'.\n"; + } + + // + // Remove older files. + // + + cleanup(caches_); + + // + // Empty the repository. + // + + empty(); + + return 1; +} + +int Keeper::cleanupImages() +{ + #ifdef TEST + *logofs << "Keeper: Looking for image directory in '" + << root_ << "'.\n" << logofs_flush; + #endif + + char *imagesPath = new char[strlen(root_) + strlen("/images") + 1]; + + if (imagesPath == NULL) + { + return -1; + } + + strcpy(imagesPath, root_); + strcat(imagesPath, "/images"); + + // + // Check if the cache directory does exist. + // + + struct stat dirStat; + + if (stat(imagesPath, &dirStat) == -1) + { + #ifdef WARNING + *logofs << "Keeper: WARNING! Can't stat NX images cache directory '" + << imagesPath << ". Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Can't stat NX images cache directory '" + << imagesPath << ". Error is " << EGET() << " '" + << ESTR() << "'.\n"; + + delete [] imagesPath; + + return -1; + } + + // + // Check any of the 16 directories in the + // images root path. + // + + char *digitPath = new char[strlen(imagesPath) + 5]; + + strcpy(digitPath, imagesPath); + + for (char digit = 0; digit < 16; digit++) + { + // + // Give up if we received a signal or + // our parent is gone. + // + + if (signal_ != 0) + { + #ifdef TEST + *logofs << "Keeper: Signal detected. Aborting.\n" + << logofs_flush; + #endif + + goto KeeperCleanupImagesAbort; + } + else if (parent_ != getppid() || parent_ == 1) + { + #ifdef WARNING + *logofs << "Keeper: WARNING! Parent process appears " + << "to be dead. Returning.\n" + << logofs_flush; + #endif + + goto KeeperCleanupImagesAbort; + + return 0; + } + + sprintf(digitPath + strlen(imagesPath), "/I-%01X", digit); + + // + // Add to the repository all the files + // in the given directory. + // + + collect(digitPath); + } + + delete [] imagesPath; + delete [] digitPath; + + // + // Remove the oldest files. + // + + cleanup(images_); + + // + // Empty the repository. + // + + empty(); + + return 1; + +KeeperCleanupImagesAbort: + + delete [] imagesPath; + delete [] digitPath; + + empty(); + + return 0; +} + +int Keeper::collect(const char *path) +{ + #ifdef TEST + *logofs << "Keeper: Looking for files in directory '" + << path << "'.\n" << logofs_flush; + #endif + + DIR *cacheDir = opendir(path); + + if (cacheDir != NULL) + { + File *file; + + dirent *dirEntry; + + struct stat fileStat; + + int baseSize = strlen(path); + int fileSize = baseSize + 3 + MD5_LENGTH * 2 + 1; + + int n = 0; + int s = 0; + + while (((dirEntry = readdir(cacheDir)) != NULL)) + { + if (s++ % ONCE == 0) usleep(sleep_ * 1000); + + if (signal_ != 0) break; + + if (strcmp(dirEntry -> d_name, ".") == 0 || + strcmp(dirEntry -> d_name, "..") == 0) + { + continue; + } + + n++; + + if (strlen(dirEntry -> d_name) == (MD5_LENGTH * 2 + 2) && + (strncmp(dirEntry -> d_name, "I-", 2) == 0 || + strncmp(dirEntry -> d_name, "S-", 2) == 0 || + strncmp(dirEntry -> d_name, "C-", 2) == 0)) + { + file = new File(); + + char *fileName = new char[fileSize]; + + if (file == NULL || fileName == NULL) + { + #ifdef WARNING + *logofs << "Keeper: WARNING! Can't add file '" + << dirEntry -> d_name << "' to repository.\n" + << logofs_flush; + #endif + + delete [] fileName; + + delete file; + + continue; + } + + strcpy(fileName, path); + strcpy(fileName + baseSize, "/"); + strcpy(fileName + baseSize + 1, dirEntry -> d_name); + + file -> name_ = fileName; + + #ifdef DEBUG + *logofs << "Keeper: Adding file '" << file -> name_ + << "'.\n" << logofs_flush; + #endif + + if (stat(file -> name_, &fileStat) == -1) + { + #ifdef WARNING + *logofs << "Keeper: WARNING! Can't stat NX file '" + << file -> name_ << ". Error is " << EGET() + << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + delete file; + + continue; + } + + file -> size_ = fileStat.st_size; + file -> time_ = fileStat.st_mtime; + + files_ -> insert(T_files::value_type(file)); + + total_ += file -> size_; + } + } + + closedir(cacheDir); + + if (n == 0) + { + time_t now = time(NULL); + + if (now > 0 && stat(path, &fileStat) == 0) + { + #ifdef TEST + *logofs << "Keeper: Empty NX subdirectory '" << path + << "' unused since " << now - fileStat.st_mtime + << " S.\n" << logofs_flush; + #endif + + if (now - fileStat.st_mtime > EMPTY_DIR_TIME) + { + #ifdef TEST + *logofs << "Keeper: Removing empty NX subdirectory '" + << path << "'.\n" << logofs_flush; + #endif + + rmdir(path); + } + } + } + } + else + { + #ifdef WARNING + *logofs << "Keeper: WARNING! Can't open NX subdirectory '" + << path << ". Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Can't open NX subdirectory '" + << path << ". Error is " << EGET() << " '" << ESTR() + << "'.\n"; + } + + return 1; +} + +int Keeper::cleanup(int threshold) +{ + #ifdef TEST + *logofs << "Keeper: Deleting the oldest files with " + << files_ -> size() << " elements threshold " + << threshold << " and size " << total_ << ".\n" + << logofs_flush; + #endif + + // + // At least some versions of the standard + // library don't allow erasing an element + // while looping. This is not the most ef- + // ficient way to release the objects, but + // it's better than making a copy of the + // container. + // + + while (total_ > threshold && files_ -> size() > 0) + { + T_files::iterator i = files_ -> begin(); + + File *file = *i; + + #ifdef TEST + *logofs << "Keeper: Removing '" << file -> name_ + << "' with time " << file -> time_ << " and size " + << file -> size_ << ".\n" << logofs_flush; + #endif + + unlink(file -> name_); + + total_ -= file -> size_; + + #ifdef DEBUG + *logofs << "Keeper: Going to delete the file at " + << file << " while cleaning up.\n" + << logofs_flush; + #endif + + delete file; + + #ifdef DEBUG + *logofs << "Keeper: Going to erase the element " + << "while cleaning up.\n" + << logofs_flush; + #endif + + files_ -> erase(i); + } + + #ifdef TEST + *logofs << "Keeper: Bytes in repository are " + << total_ << ".\n" << logofs_flush; + #endif + + return 1; +} + +void Keeper::empty() +{ + #ifdef TEST + *logofs << "Keeper: Getting rid of files in repository.\n" + << logofs_flush; + #endif + + while (files_ -> size() > 0) + { + T_files::iterator i = files_ -> begin(); + + File *file = *i; + + #ifdef DEBUG + *logofs << "Keeper: Going to delete the file at " + << file << " while emptying.\n" + << logofs_flush; + #endif + + delete file; + + #ifdef DEBUG + *logofs << "Keeper: Going to erase the element " + << "while emptying.\n" + << logofs_flush; + #endif + + files_ -> erase(i); + } + + total_ = 0; + + #ifdef TEST + *logofs << "Keeper: Bytes in repository are " + << total_ << ".\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/Keeper.h b/nxcomp/src/Keeper.h new file mode 100644 index 000000000..b440beceb --- /dev/null +++ b/nxcomp/src/Keeper.h @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Keeper_H +#define Keeper_H + +#include "Misc.h" +#include "Types.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Define this to check how many file +// nodes are allocated and deallocated. +// + +#undef REFERENCES + +class Keeper; + +class File +{ + friend class Keeper; + + public: + + File(); + + ~File(); + + // + // Allow sort by time and size. If time + // is the same, keep the bigger element. + // + + bool compare(File *b) const; + + private: + + char *name_; + + int size_; + time_t time_; + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +class Keeper +{ + public: + + Keeper(int caches, int images, const char *root, + int sleep, int parent); + + ~Keeper(); + + // + // Call this just once. + // + + int cleanupCaches(); + + // + // Call this at any given interval. + // + + int cleanupImages(); + + // + // Call this if it's time to exit. + // + + void setSignal(int signal) + { + signal_ = signal; + } + + int getSignal() + { + return signal_; + } + + int getParent() + { + return parent_; + } + + private: + + // + // Get a list of files in directory. + // + + int collect(const char *path); + + // + // Sort the collected files according to + // last modification time and delete the + // older ones until disk size is below + // the threshold. + // + + int cleanup(int threshold); + + // + // Empty the files repository. + // + + void empty(); + + // + // Size in bytes of total allowed + // storage for persistent caches. + // + + int caches_; + + // + // Size in bytes of total allowed + // storage for images cache. + // + + int images_; + + // + // Path of the NX root directory. + // + + char *root_; + + // + // The little delay to be introduced + // before reading a new entry. + // + + int sleep_; + + // + // Total size of files in repository. + // + + int total_; + + // + // The parent process, so we can exit + // if it is gone. + // + + int parent_; + + // + // Set if we need to give up because + // of a signal. + // + + int signal_; + + // + // Repository where to collect files. + // + + T_files *files_; +}; + +#endif /* Keeper_H */ + diff --git a/nxcomp/src/List.cpp b/nxcomp/src/List.cpp new file mode 100644 index 000000000..b2db7151c --- /dev/null +++ b/nxcomp/src/List.cpp @@ -0,0 +1,112 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "List.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Define this to know how many instances +// are allocated and deallocated. +// + +#undef REFERENCES + +#ifdef REFERENCES + +int List::references_ = 0; + +#endif + +List::List() +{ + #ifdef REFERENCES + + references_++; + + *logofs << "List: Created new List at " + << this << " out of " << references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +List::~List() +{ + #ifdef REFERENCES + + references_--; + + *logofs << "List: Deleted List at " + << this << " out of " << references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +void List::remove(int value) +{ + for (T_list::iterator i = list_.begin(); i != list_.end(); i++) + { + if (*i == value) + { + list_.erase(i); + + return; + } + } + + #ifdef PANIC + *logofs << "List: PANIC! Should not try to remove " + << "an element not found in the list.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Should not try to remove " + << "an element not found in the list.\n"; + + HandleAbort(); +} + +void List::rotate() +{ + if (list_.size() > 1) + { + int value = *(list_.begin()); + + list_.pop_front(); + + list_.push_back(value); + } +} diff --git a/nxcomp/src/List.h b/nxcomp/src/List.h new file mode 100644 index 000000000..31c80f835 --- /dev/null +++ b/nxcomp/src/List.h @@ -0,0 +1,95 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef List_H +#define List_H + +#include "Misc.h" +#include "Types.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Define this to log when lists are +// allocated and deallocated. +// + +#undef REFERENCES + +class List +{ + public: + + List(); + + ~List(); + + int getSize() + { + return list_.size(); + } + + T_list &getList() + { + return list_; + } + + T_list copyList() + { + return list_; + } + + void add(int value) + { + list_.push_back(value); + } + + void remove(int value); + + void rotate(); + + private: + + // + // The list container. + // + + T_list list_; + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +#endif /* List_H */ diff --git a/nxcomp/src/ListFontsReply.cpp b/nxcomp/src/ListFontsReply.cpp new file mode 100644 index 000000000..16be522a1 --- /dev/null +++ b/nxcomp/src/ListFontsReply.cpp @@ -0,0 +1,213 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ListFontsReply.h" + +#include "ServerCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef DUMP +#undef TEST +#undef DEBUG + +ListFontsReplyStore::ListFontsReplyStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = LISTFONTSREPLY_ENABLE_CACHE; + enableData = LISTFONTSREPLY_ENABLE_DATA; + enableSplit = LISTFONTSREPLY_ENABLE_SPLIT; + + // Since ProtoStep7 (#issue 108) + enableCompress = LISTFONTSREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = LISTFONTSREPLY_DATA_LIMIT; + dataOffset = LISTFONTSREPLY_DATA_OFFSET; + + cacheSlots = LISTFONTSREPLY_CACHE_SLOTS; + cacheThreshold = LISTFONTSREPLY_CACHE_THRESHOLD; + cacheLowerThreshold = LISTFONTSREPLY_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +ListFontsReplyStore::~ListFontsReplyStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int ListFontsReplyStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ListFontsReplyMessage *listFontsReply = (ListFontsReplyMessage *) message; + + // + // Here is the fingerprint. + // + + listFontsReply -> number_of_names = GetUINT(buffer + 8, bigEndian); + + // + // Clean up padding bytes. + // + + if ((int) size > dataOffset) + { + unsigned int current; + unsigned int length; + unsigned int nstringInNames; + + unsigned char *end = NULL; + unsigned char *pad = NULL; + + #ifdef DUMP + + *logofs << "\n" << logofs_flush; + + *logofs << "Number of STRING8 " << listFontsReply -> number_of_names << ".\n" << logofs_flush; + + *logofs << "Size " << size << ".\n" << logofs_flush; + + DumpHexData(buffer, size); + + *logofs << "\n" << logofs_flush; + + #endif + + length = LISTFONTSREPLY_DATA_OFFSET; + + for (nstringInNames = 0; + nstringInNames < listFontsReply -> number_of_names && + listFontsReply -> number_of_names > 0; + nstringInNames++) + { + // + // Start with offset LISTFONTSREPLY_DATA_OFFSET 32. + // + + current = buffer[length]; + + length += current + 1; + + #ifdef DUMP + *logofs << "\nString number : " << nstringInNames << " Current length : " + << current << "\n" << logofs_flush; + #endif + } + + #ifdef DUMP + *logofs << "\nFinal length " << length << "\n" << logofs_flush; + #endif + + end = ((unsigned char *) buffer) + size; + + for (pad = ((unsigned char *) buffer) + length; pad < end; pad++) + { + *pad = 0; + + #ifdef DUMP + *logofs << "\nPadding ." << "\n" << logofs_flush; + #endif + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int ListFontsReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ListFontsReplyMessage *listFontsReply = (ListFontsReplyMessage *) message; + + // + // Fill all the message's fields. + // + + PutUINT(listFontsReply -> number_of_names, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void ListFontsReplyStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + ListFontsReplyMessage *listFontsReply = (ListFontsReplyMessage *) message; + + *logofs << name() << ": Identity number_of_names " + << listFontsReply -> number_of_names << ", size " + << listFontsReply -> size_ << ".\n"; + + #endif +} + +void ListFontsReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Field number_of_names. + // + + md5_append(md5_state_, buffer + 8, 2); +} diff --git a/nxcomp/src/ListFontsReply.h b/nxcomp/src/ListFontsReply.h new file mode 100644 index 000000000..c731878e0 --- /dev/null +++ b/nxcomp/src/ListFontsReply.h @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ListFontsReply_H +#define ListFontsReply_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define LISTFONTSREPLY_ENABLE_CACHE 1 +#define LISTFONTSREPLY_ENABLE_DATA 1 +#define LISTFONTSREPLY_ENABLE_SPLIT 0 + +#define LISTFONTSREPLY_DATA_LIMIT 1048576 - 32 +#define LISTFONTSREPLY_DATA_OFFSET 32 + +#define LISTFONTSREPLY_CACHE_SLOTS 200 +#define LISTFONTSREPLY_CACHE_THRESHOLD 20 +#define LISTFONTSREPLY_CACHE_LOWER_THRESHOLD 5 + +#define LISTFONTSREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +// +// The message class. +// + +class ListFontsReplyMessage : public Message +{ + friend class ListFontsReplyStore; + + public: + + ListFontsReplyMessage() + { + } + + ~ListFontsReplyMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned short int number_of_names; +}; + +class ListFontsReplyStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + ListFontsReplyStore(StaticCompressor *compressor); + + virtual ~ListFontsReplyStore(); + + virtual const char *name() const + { + return "ListFontsReply"; + } + + virtual unsigned char opcode() const + { + return X_ListFonts; + } + + virtual unsigned int storage() const + { + return sizeof(ListFontsReplyMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new ListFontsReplyMessage(); + } + + virtual Message *create(const Message &message) const + { + return new ListFontsReplyMessage((const ListFontsReplyMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (ListFontsReplyMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* ListFontsReply_H */ diff --git a/nxcomp/src/Loop.cpp b/nxcomp/src/Loop.cpp new file mode 100644 index 000000000..238e503b7 --- /dev/null +++ b/nxcomp/src/Loop.cpp @@ -0,0 +1,16693 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Misc.h" + +#ifdef __sun +#include +#endif + +// +// MacOSX 10.4 defines socklen_t. This is +// intended to ensure compatibility with +// older versions. +// + +#ifdef __APPLE__ +#include +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_3 +typedef int socklen_t; +#endif +#endif + +#ifdef _AIX +#include +#include +#endif + +#ifndef __CYGWIN32__ +#include +#endif + +// +// NX include files. +// + +#include "NX.h" +#include "NXalert.h" + +#include "Misc.h" +#include "Control.h" +#include "Socket.h" +#include "Statistics.h" +#include "Auth.h" +#include "Keeper.h" +#include "Agent.h" + +#include "ClientProxy.h" +#include "ServerProxy.h" + +#include "Message.h" +#include "ChannelEndPoint.h" + +// +// System specific defines. +// + + +// +// HP-UX hides this define. +// + +#if defined(hpux) && !defined(RLIM_INFINITY) + +#define RLIM_INFINITY 0x7fffffff + +#endif + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Enable log output in signal handler. +// This is likely to hang the proxy at +// random, at least on Linux. +// + +#undef UNSAFE + +// +// Let all logs go to the standard error. +// This is useful to interleave the Xlib +// log output with the proxy output in a +// single file. +// + +#undef MIXED + +// +// Define this to check if the client and +// server caches match at shutdown. This +// is a test facility as it requires that +// both proxies are running on the same +// host. +// + +#undef MATCH + +// +// If defined, reduce the size of the log +// file and be sure it never exceeds the +// limit. +// + +#undef QUOTA + +// +// If defined, force very strict limits for +// the proxy tokens and force the proxy to +// enter often in congestion state. +// + +#undef STRICT + +// +// Print a line in the log if the time we +// spent inside the select or handling the +// messages exceeded a given time value. +// + +#undef TIME + +// +// This can be useful when testing the forwarding +// of the SSHD connection by nxssh to the agent. +// The debug output will go to a well known file +// that will be opened also by nxssh when BINDER +// is enabled there. +// + +#undef BINDER + +// +// Define this to override the limits on +// the core dump size. +// + +#define COREDUMPS + +// +// Upper limit of pre-allocated buffers +// for string parameters. +// + +#define DEFAULT_STRING_LENGTH 256 + +// +// Maximum length of remote options data +// passed by peer proxy at startup. +// + +#define DEFAULT_REMOTE_OPTIONS_LENGTH 512 + +// +// Maximum length of NX display string. +// + +#define DEFAULT_DISPLAY_OPTIONS_LENGTH 1024 + +// +// Maximum number of cache file names to +// send to the server side. +// + +#define DEFAULT_REMOTE_CACHE_ENTRIES 100 + +// +// Maximum length of remote options string +// that can be received from the peer proxy. +// + +#define MAXIMUM_REMOTE_OPTIONS_LENGTH 4096 + +// +// Macro is true if we determined our proxy +// mode. +// + +#define WE_SET_PROXY_MODE (control -> ProxyMode != proxy_undefined) + +// +// Macro is true if our side is the one that +// should connect to remote. +// + +#define WE_INITIATE_CONNECTION (connectSocket.enabled()) + +// +// Is true if we must provide our credentials +// to the remote peer. +// + +#define WE_PROVIDE_CREDENTIALS (control -> ProxyMode == proxy_server) + +// +// Is true if we listen for a local forwarder +// that will tunnel the traffic through a SSH +// or HTTP link. +// + +#define WE_LISTEN_FORWARDER (control -> ProxyMode == proxy_server && \ + listenSocket.enabled()) + +// +// You must define FLUSH in Misc.h if +// you want an immediate flush of the +// log output. +// + +ostream *logofs = NULL; + +// +// Other stream destriptors used for +// logging. +// + +ostream *statofs = NULL; +ostream *errofs = NULL; + +// +// Save standard error's rdbuf here +// and restore it when exiting. +// + +static streambuf *errsbuf = NULL; + +// +// Allow faults to be recovered by +// jumping back into the main loop. +// + +jmp_buf context; + +// +// Provide operational parameters. +// + +Control *control = NULL; + +// +// Collect and print statistics. +// + +Statistics *statistics = NULL; + +// +// Keep data for X11 authentication. +// + +Auth *auth = NULL; + +// +// This class makes the hard work. +// + +Proxy *proxy = NULL; + +// +// Used to handle memory-to-memory +// transport to the X agent. +// + +Agent *agent = NULL; + +// +// The image cache house-keeping class. +// + +Keeper *keeper = NULL; + +// +// Callback set by the child process +// to be notified about signals. +// + +int (*handler)(int) = NULL; + +// +// Signal handling functions. +// + +void DisableSignals(); +void EnableSignals(); +void InstallSignals(); + +static void RestoreSignals(); +static void HandleSignal(int signal); + +// +// Signal handling utilities. +// + +static void InstallSignal(int signal, int action); +static void RestoreSignal(int signal); + +static int HandleChildren(); + +int HandleChild(int child); +static int CheckChild(int pid, int status); +static int WaitChild(int child, const char *label, int force); + +int CheckParent(const char *name, const char *type, int parent); + +void RegisterChild(int child); + +static int CheckAbort(); + +// +// Timer handling utilities. +// + +void SetTimer(int timeout); +void ResetTimer(); + +static void HandleTimer(int signal); + +// +// Kill or check a running child. +// + +static int KillProcess(int pid, const char *label, int signal, int wait); +static int CheckProcess(int pid, const char *label); + +// +// Macros used to test the pid of a child. +// + +#define IsFailed(pid) ((pid) < 0) +#define IsRunning(pid) ((pid) > 1) +#define IsNotRunning(pid) ((pid) == 0) +#define IsRestarting(pid) ((pid) == 1) + +#define SetNotRunning(pid) ((pid) = 0) +#define SetRestarting(pid) ((pid) = 1) + +// +// Start or restart the house-keeper process. +// + +static int StartKeeper(); + +// +// Cleanup functions. +// + +void CleanupConnections(); +void CleanupListeners(); +void CleanupSockets(); +void CleanupGlobal(); + +static void CleanupChildren(); +static void CleanupLocal(); +static void CleanupKeeper(); +static void CleanupStreams(); + +// +// Loop forever until the connections +// to the peer proxy is dropped. +// + +static void WaitCleanup(); + +// +// Initialization functions. +// + +static int InitBeforeNegotiation(); +static int SetupProxyConnection(); +static int InitAfterNegotiation(); +static int SetupProxyInstance(); +static int SetupAuthInstance(); +static int SetupAgentInstance(); + +static int SetupTcpSocket(); +static int SetupUnixSocket(); +static int SetupServiceSockets(); +static int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr, + unsigned int &xServerAddrLength); + +// +// Setup a listening socket and accept +// a new connection. +// + +static int ListenConnection(ChannelEndPoint &endPoint, const char *label); +static int ListenConnectionTCP(const char *host, long port, const char *label); +static int ListenConnectionUnix(const char *path, const char *label); +static int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label); +static int AcceptConnection(int fd, int domain, const char *label); + +// +// Other convenience functions. +// + +static int PrepareProxyConnectionTCP(char** hostName, long int* portNum, int* timeout, int* proxyFD, int* reason); +static int PrepareProxyConnectionUnix(char** path, int* timeout, int* proxyFD, int* reason); + +static int WaitForRemote(ChannelEndPoint &socketAddress); +static int ConnectToRemote(ChannelEndPoint &socketAddress); + +static int SendProxyOptions(int fd); +static int SendProxyCaches(int fd); +static int ReadProxyVersion(int fd); +static int ReadProxyOptions(int fd); +static int ReadProxyCaches(int fd); +static int ReadForwarderVersion(int fd); +static int ReadForwarderOptions(int fd); + +static int ReadRemoteData(int fd, char *buffer, int size, char stop); +static int WriteLocalData(int fd, const char *buffer, int size); + +static void PrintVersionInfo(); +static void PrintProcessInfo(); +static void PrintConnectionInfo(); +static void PrintUsageInfo(const char *option, const int error); +static void PrintOptionIgnored(const char *type, const char *name, const char *value); + +// +// This is not static to avoid a warning. +// + +void PrintCopyrightInfo(); + +static const char *GetOptions(const char *options); +static const char *GetArg(int &argi, int argc, const char **argv); +static int CheckArg(const char *type, const char *name, const char *value); +static int ParseArg(const char *type, const char *name, const char *value); +static int ValidateArg(const char *type, const char *name, const char *value); +static void SetAndValidateChannelEndPointArg(const char *type, const char *name, const char *value, + ChannelEndPoint &endPoint); +static int LowercaseArg(const char *type, const char *name, char *value); +static int CheckSignal(int signal); + +extern "C" +{ + int ParseCommandLineOptions(int argc, const char **argv); + int ParseEnvironmentOptions(const char *env, int force); + int ParseBindOptions(char **host, int *port); +} + +static int ParseFileOptions(const char *file); +static int ParseRemoteOptions(char *opts); +static int ParseForwarderOptions(char *opts); + +// +// These functions are used to parse literal +// values provided by the user and set the +// control parameters accordingly. +// + +static int ParseLinkOption(const char *opt); +static int ParseBitrateOption(const char *opt); +static int ParseCacheOption(const char *opt); +static int ParseShmemOption(const char *opt); +static int ParseImagesOption(const char *opt); +static int ParsePackOption(const char *opt); + +// +// Set host and port where NX proxy is supposed +// to be listening in case such parameters are +// given on the command line. +// + +static int ParseHostOption(const char *opt, char *host, long &port); + +// +// Translate a font server port specification +// to the corresponding Unix socket path. +// + +static int ParseFontPath(char *path); + +// +// Translate a pack method id in a literal. +// + +static int ParsePackMethod(const int method, const int quality); + +// +// Try to increase the size of the allowed +// core dumps. +// + +static int SetCore(); + +// +// Set the proxy mode to either client or +// server. +// + +static int SetMode(int mode); + +// +// Determine the path of the NX_* directories +// from the environment. +// + +static int SetDirectories(); + +// +// Set the defaults used for the log file and +// statistics. +// + +static int SetLogs(); + +// +// Check if local and remote protocol versions +// are compatible and, eventually, downgrade +// local version to the minimum level that is +// known to work. +// + +static int SetVersion(); + +// +// Setup the listening TCP ports used for the +// additional channels according to user's +// wishes. +// + +static int SetPorts(); + +// +// Set the maximum number of open descriptors. +// + +static int SetDescriptors(); + +// +// Set the path used for choosing the cache. +// It must be selected after determining the +// session type. +// + +static int SetCaches(); + +// +// Initialize, one after the other, all the +// configuration parameters. +// + +static int SetParameters(); + +// +// Set the specific configuration parameter. +// + +static int SetSession(); +static int SetStorage(); +static int SetShmem(); +static int SetPack(); +static int SetImages(); +static int SetLimits(); + +// +// Set up the control parameters based on +// the link speed negotiated between the +// proxies. +// + +static int SetLink(); + +static int SetLinkModem(); +static int SetLinkIsdn(); +static int SetLinkAdsl(); +static int SetLinkWan(); +static int SetLinkLan(); + +// +// Adjust the compression parameters. +// + +static int SetCompression(); + +static int SetCompressionModem(); +static int SetCompressionIsdn(); +static int SetCompressionAdsl(); +static int SetCompressionWan(); +static int SetCompressionLan(); + +// +// Determine the NX paths based on the +// user's parameters or the environment. +// + +char *GetClientPath(); + +static char *GetSystemPath(); +static char *GetHomePath(); +static char *GetTempPath(); +static char *GetRootPath(); +static char *GetCachePath(); +static char *GetImagesPath(); +static char *GetSessionPath(); +static char *GetLastCache(char *list, const char *path); + +static int OpenLogFile(char *name, ostream *&stream); +static int ReopenLogFile(char *name, ostream *&stream, int limit); + +// +// Perform operations on the managed +// descriptors in the main loop. +// + +static void handleCheckSessionInLoop(); +static void handleCheckBitrateInLoop(); + +#if defined(TEST) || defined(INFO) +static void handleCheckSelectInLoop(int &setFDs, fd_set &readSet, + fd_set &writeSet, T_timestamp selectTs); +static void handleCheckResultInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, + fd_set &writeSet, struct timeval &selectTs, + struct timeval &startTs); +static void handleCheckStateInLoop(int &setFDs); +#endif + +static void handleCheckSessionInConnect(); + +static inline void handleSetReadInLoop(fd_set &readSet, int &setFDs, struct timeval &selectTs); +static inline void handleSetWriteInLoop(fd_set &writeSet, int &setFDs, struct timeval &selectTs); +static inline void handleSetListenersInLoop(fd_set &writeSet, int &setFDs); +static inline void handleSetAgentInLoop(int &setFDs, fd_set &readSet, fd_set &writeSet, + struct timeval &selectTs); + +static void handleAlertInLoop(); +static void handleStatisticsInLoop(); + +static inline void handleAgentInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, + fd_set &writeSet, struct timeval &selectTs); +static inline void handleAgentLateInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, + fd_set &writeSet, struct timeval &selectTs); + +static inline void handleReadableInLoop(int &resultFDs, fd_set &readSet); +static inline void handleWritableInLoop(int &resultFDs, fd_set &writeSet); + +static inline void handleRotateInLoop(); +static inline void handleEventsInLoop(); +static inline void handleFlushInLoop(); + +// +// Manage the proxy link during the negotiation +// phase. +// + +static void handleNegotiationInLoop(int &setFDs, fd_set &readSet, + fd_set &writeSet, T_timestamp &selectTs); + +// +// Print the 'terminating' messages in the +// session log. +// + +static inline void handleTerminatingInLoop(); +static inline void handleTerminatedInLoop(); + +// +// Monitor the size of the log file. +// + +static void handleLogReopenInLoop(T_timestamp &logsTs, T_timestamp &nowTs); + +// +// Directory where the NX binaries and libraries reside. +// + +static char systemDir[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Directory used for temporary files. +// + +static char tempDir[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Actually the full path to the client. +// + +static char clientDir[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// User's home directory. +// + +static char homeDir[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Root of directory structure to be created by proxy. +// + +static char rootDir[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Root of statistics and log files to be created by proxy. +// + +static char sessionDir[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Log files for errors and statistics. Error log is +// the place where we print also debug informations. +// Both files are closed, deleted and reopened as +// their size exceed the limit set in control class. +// The session log is not reopened, as it is used by +// the NX client and server to track the advance of +// the session. +// + +static char errorsFileName[DEFAULT_STRING_LENGTH] = { 0 }; +static char statsFileName[DEFAULT_STRING_LENGTH] = { 0 }; +static char sessionFileName[DEFAULT_STRING_LENGTH] = { 0 }; +static char optionsFileName[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// String literal representing selected link speed +// parameter. Value is translated in control values +// used by proxies to stay synchronized. +// + +static char linkSpeedName[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// String literal representing selected +// cache size. +// + +static char cacheSizeName[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// String literal representing selected +// shared memory segment size. +// + +static char shsegSizeName[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// String literal of images cache size. +// + +static char imagesSizeName[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// String literal for bandwidth limit. +// + +static char bitrateLimitName[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// String literal for image packing method. +// + +static char packMethodName[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Product name provided by the server or client. +// + +static char productName[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Its corresponding value from NXpack.h. +// + +static int packMethod = -1; +static int packQuality = -1; + +// +// String literal for session type. Persistent caches +// are searched in directory whose name matches this +// parameter. +// + +static char sessionType[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Unique id assigned to session. It is used as +// name of directory where all files are placed. +// + +static char sessionId[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Set if we already parsed the options. +// + +static int parsedOptions = 0; +static int parsedCommand = 0; + +// +// Buffer data received from the remote proxy at +// session negotiation. +// + +static char remoteData[MAXIMUM_REMOTE_OPTIONS_LENGTH] = { 0 }; +static int remotePosition = 0; + +// +// Main loop file descriptors. +// + +static int tcpFD = -1; +static int unixFD = -1; +static int cupsFD = -1; +static int auxFD = -1; +static int smbFD = -1; +static int mediaFD = -1; +static int httpFD = -1; +static int fontFD = -1; +static int slaveFD = -1; +static int proxyFD = -1; + +// +// Used for internal communication +// with the X agent. +// + +static int agentFD[2] = { -1, -1 }; + +// +// Flags determining which protocols and +// ports are forwarded. +// + +int useUnixSocket = 1; + +static int useTcpSocket = 1; +static int useCupsSocket = 0; +static int useAuxSocket = 0; +static int useSmbSocket = 0; +static int useMediaSocket = 0; +static int useHttpSocket = 0; +static int useFontSocket = 0; +static int useSlaveSocket = 0; +static int useAgentSocket = 0; + +// +// Set if the launchd service is running +// and its socket must be used as X socket. +// + +static int useLaunchdSocket = 0; + +// +// Set by user if he/she wants to modify +// the default TCP_NODELAY option as set +// in control. +// + +static int useNoDelay = -1; + +// +// Set if user wants to override default +// flush timeout set according to link. +// + +static int usePolicy = -1; + +// +// Set if user wants to hide the RENDER +// extension or wants to short-circuit +// some simple replies at client side. +// + +static int useRender = -1; +static int useTaint = -1; + +// +// Set if the user wants to reduce the +// nominal size of the token messages +// exchanged between the proxies. +// + +static int useStrict = -1; + +// +// Set if the proxy is running as part +// of SSH on the client. +// + +static int useEncryption = -1; + +// +// Name of Unix socket created by the client proxy to +// accept client connections. File must be unlinked +// by cleanup function. +// + +static char unixSocketName[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Other parameters. +// + +static char acceptHost[DEFAULT_STRING_LENGTH] = { 0 }; +static char displayHost[DEFAULT_STRING_LENGTH] = { 0 }; +static char authCookie[DEFAULT_STRING_LENGTH] = { 0 }; + +static int loopbackBind = DEFAULT_LOOPBACK_BIND; +static int proxyPort = DEFAULT_NX_PROXY_PORT; +static int xPort = DEFAULT_NX_X_PORT; + +// +// Used to setup the connection the real +// X display socket. +// + +static int xServerAddrFamily = -1; +static sockaddr *xServerAddr = NULL; +static unsigned int xServerAddrLength = 0; + +// +// The representation of a Unix socket path or +// a bind address, denoting where the local proxy +// will await the peer connection. +// + +static ChannelEndPoint listenSocket; + +// +// The TCP host and port or Unix file socket where +// the remote proxy will be contacted. +// + +static ChannelEndPoint connectSocket; + +// +// Helper channels are disabled by default. +// + +static ChannelEndPoint cupsPort; +static ChannelEndPoint auxPort; +static ChannelEndPoint smbPort; +static ChannelEndPoint mediaPort; +static ChannelEndPoint httpPort; +static ChannelEndPoint slavePort; + +// +// Can be either a port number or a Unix +// socket. +// + +static char fontPort[DEFAULT_STRING_LENGTH] = { 0 }; + +// +// Host and port where the existing proxy +// is running. +// + +static char bindHost[DEFAULT_STRING_LENGTH] = { 0 }; +static int bindPort = -1; + +// +// Pointers to the callback functions and +// parameter set by the agent +// + +static void (*flushCallback)(void *, int) = NULL; +static void *flushParameter = NULL; + +static void (*statisticsCallback)(void *, int) = NULL; +static void *statisticsParameter = NULL; + +// +// State variables shared between the init +// function and the main loop. +// + +T_timestamp initTs; +T_timestamp startTs; +T_timestamp logsTs; +T_timestamp nowTs; + +int diffTs; + +// +// This is set to the main proxy process id. +// + +int lastProxy = 0; + +// +// Set to last dialog process launched by proxy. +// + +int lastDialog = 0; + +// +// Set to watchdog process launched by proxy. +// + +int lastWatchdog = 0; + +// +// Set if a cache house-keeper process is running. +// + +int lastKeeper = 0; + +// +// Let an inner routine register the pid of a slave +// process. +// + +static int lastChild = 0; + +// +// Exit code of the last child process exited. +// + +static int lastStatus = 0; + +// +// Set if shutdown was requested through a signal. +// + +static int lastKill = 0; + +// +// Set if the agent confirmed the destruction of +// the NX transport. +// + +static int lastDestroy = 0; + +// +// This is set to the code and local flag of the +// last requested alert. +// + +static struct +{ + int code; + int local; + +} lastAlert; + +// +// Manage the current signal masks. +// + +static struct +{ + sigset_t saved; + + int blocked; + int installed; + + int enabled[32]; + int forward[32]; + + struct sigaction action[32]; + +} lastMasks; + +// +// Manage the current timer. +// + +static struct +{ + struct sigaction action; + struct itimerval value; + struct timeval start; + struct timeval next; + +} lastTimer; + +// +// This is set to last signal received in handler. +// + +static int lastSignal = 0; + +// +// Set to the last time bytes readable were queried +// by the agent. +// + +static T_timestamp lastReadableTs = nullTimestamp(); + +// +// Here are interfaces declared in NX.h. +// + +int NXTransProxy(int fd, int mode, const char* options) +{ + // + // Let the log temporarily go to the standard + // error. Be also sure we have a jump context, + // in the case any subsequent operation will + // cause a cleanup. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + if (setjmp(context) == 1) + { + #ifdef TEST + *logofs << "NXTransProxy: Out of the long jump with pid '" + << lastProxy << "'.\n" << logofs_flush; + #endif + + return -1; + } + + // + // Check if have already performed a parsing of + // parameters, as in the case we are running as + // a stand-alone process. If needed create the + // parameters repository + // + + if (control == NULL) + { + control = new Control(); + } + + lastProxy = getpid(); + + #ifdef TEST + *logofs << "NXTransProxy: Main process started with pid '" + << lastProxy << "'.\n" << logofs_flush; + #endif + + SetMode(mode); + + if (mode == NX_MODE_CLIENT) + { + if (fd != NX_FD_ANY) + { + #ifdef TEST + + *logofs << "NXTransProxy: Agent descriptor for X client connections is FD#" + << fd << ".\n" << logofs_flush; + + *logofs << "NXTransProxy: Disabling listening on further X client connections.\n" + << logofs_flush; + + #endif + + useTcpSocket = 0; + useUnixSocket = 0; + useAgentSocket = 1; + + agentFD[1] = fd; + } + } + else if (mode == NX_MODE_SERVER) + { + if (fd != NX_FD_ANY) + { + #ifdef TEST + *logofs << "NXTransProxy: PANIC! Agent descriptor for X server connections " + << "not supported yet.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Agent descriptor for X server connections " + << "not supported yet.\n"; + + return -1; + } + } + + const char *env = GetOptions(options); + + if (ParseEnvironmentOptions(env, 0) < 0) + { + cerr << "Error" << ": Parsing of NX transport options failed.\n"; + + return -1; + } + + // + // Set the path of the NX directories. + // + + SetDirectories(); + + // + // Open the log files. + // + + SetLogs(); + + #ifdef TEST + *logofs << "NXTransProxy: Going to run the NX transport loop.\n" + << logofs_flush; + #endif + + WaitCleanup(); + + // + // This function should never return. + // + + exit(0); +} + +void NXTransExit(int code) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + static int recurse; + + if (++recurse > 1) + { + #ifdef TEST + *logofs << "NXTransExit: Aborting process with pid '" + << getpid() << "' due to recursion through " + << "exit.\n" << logofs_flush; + #endif + + abort(); + } + + #ifdef TEST + *logofs << "NXTransExit: Process with pid '" + << getpid() << "' called exit with code '" + << code << "'.\n" << logofs_flush; + #endif + + if (control != NULL) + { + // + // Be sure that there we can detect the + // termination of the watchdog. + // + + EnableSignals(); + + // + // Close the NX transport if it was not + // shut down already. + // + + NXTransDestroy(NX_FD_ANY); + } + + exit(code); +} + +int NXTransParseCommandLine(int argc, const char **argv) +{ + return ParseCommandLineOptions(argc, argv); +} + +int NXTransParseEnvironment(const char *env, int force) +{ + return ParseEnvironmentOptions(env, force); +} + +void NXTransCleanup() +{ + HandleCleanup(); +} + +void NXTransCleanupForReconnect() +{ + HandleCleanupForReconnect(); +} + +// +// Check the parameters for subsequent +// initialization of the NX transport. +// + +int NXTransCreate(int fd, int mode, const char* options) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + // + // Be sure we have a jump context, in the + // case a subsequent operation will cause + // a cleanup. + // + + if (setjmp(context) == 1) + { + return -1; + } + + // + // Create the parameters repository + // + + if (control != NULL) + { + #ifdef PANIC + *logofs << "NXTransCreate: PANIC! The NX transport seems " + << "to be already running.\n" << logofs_flush; + #endif + + cerr << "Error" << ": The NX transport seems " + << "to be already running.\n"; + + return -1; + } + + control = new Control(); + + if (control == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error creating the NX transport.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error creating the NX transport.\n"; + + return -1; + } + + lastProxy = getpid(); + + #ifdef TEST + *logofs << "NXTransCreate: Caller process running with pid '" + << lastProxy << "'.\n" << logofs_flush; + #endif + + // + // Set the local proxy mode an parse the + // display NX options. + // + + SetMode(mode); + + const char *env = GetOptions(options); + + if (ParseEnvironmentOptions(env, 0) < 0) + { + cerr << "Error" << ": Parsing of NX transport options failed.\n"; + + return -1; + } + + // + // Set the path of the NX directories. + // + + SetDirectories(); + + // + // Open the log files. + // + + SetLogs(); + + // + // Use the provided descriptor. + // + + proxyFD = fd; + + #ifdef TEST + *logofs << "NXTransCreate: Called with NX proxy descriptor '" + << proxyFD << "'.\n" << logofs_flush; + #endif + + #ifdef TEST + *logofs << "NXTransCreate: Creation of the NX transport completed.\n" + << logofs_flush; + #endif + + return 1; +} + +// +// Tell the proxy to use the descriptor as the internal +// connection to the X client side NX agent. This will +// have the side effect of disabling listening for add- +// itional X client connections. +// + +int NXTransAgent(int fd[2]) +{ + // + // Be sure we have a jump context, in the + // case a subsequent operation will cause + // a cleanup. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + if (setjmp(context) == 1) + { + return -1; + } + + if (control == NULL) + { + cerr << "Error" << ": Can't set the NX agent without a NX transport.\n"; + + return -1; + } + else if (control -> ProxyMode != proxy_client) + { + #ifdef PANIC + *logofs << "NXTransAgent: Invalid mode while setting the NX agent.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Invalid mode while setting the NX agent.\n\n"; + + return -1; + } + + useTcpSocket = 0; + useUnixSocket = 0; + useAgentSocket = 1; + + agentFD[0] = fd[0]; + agentFD[1] = fd[1]; + + #ifdef TEST + + *logofs << "NXTransAgent: Internal descriptors for agent are FD#" + << agentFD[0] << " and FD#" << agentFD[1] << ".\n" + << logofs_flush; + + *logofs << "NXTransAgent: Disabling listening for further X client " + << "connections.\n" << logofs_flush; + + #endif + + agent = new Agent(agentFD); + + if (agent == NULL || agent -> isValid() != 1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error creating the NX memory transport .\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error creating the NX memory transport.\n"; + + HandleCleanup(); + } + + #ifdef TEST + *logofs << "NXTransAgent: Enabling memory-to-memory transport.\n" + << logofs_flush; + #endif + + return 1; +} + +int NXTransClose(int fd) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + /* + * Only handle the proxy connection. The X + * transport will take care of closing its + * end of the socket pair. + */ + + if (control != NULL && ((agent != NULL && + (fd == agentFD[0] || fd == NX_FD_ANY)) || + (fd == proxyFD || fd == NX_FD_ANY))) + { + if (proxy != NULL) + { + #ifdef TEST + *logofs << "NXTransClose: Closing down all the X connections.\n" + << logofs_flush; + #endif + + CleanupConnections(); + } + } + #ifdef TEST + else + { + *logofs << "NXTransClose: The NX transport is not running.\n" + << logofs_flush; + } + #endif + + return 1; +} + +// +// Close down the transport and free the +// allocated NX resources. +// + +int NXTransDestroy(int fd) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + if (control != NULL && ((agent != NULL && + (fd == agentFD[0] || fd == NX_FD_ANY)) || + (fd == proxyFD || fd == NX_FD_ANY))) + { + // + // Shut down the X connections and + // wait the cleanup to complete. + // + + if (proxy != NULL) + { + #ifdef TEST + *logofs << "NXTransDestroy: Closing down all the X connections.\n" + << logofs_flush; + #endif + + CleanupConnections(); + } + + #ifdef TEST + *logofs << "NXTransDestroy: Waiting for the NX transport to terminate.\n" + << logofs_flush; + #endif + + lastDestroy = 1; + + WaitCleanup(); + } + #ifdef TEST + else + { + *logofs << "NXTransDestroy: The NX transport is not running.\n" + << logofs_flush; + } + #endif + + return 1; +} + +// +// Assume that the NX transport is valid +// as long as the control class has not +// been destroyed. +// + +int NXTransRunning(int fd) +{ + return (control != NULL); +} + +int NXTransContinue(struct timeval *selectTs) +{ + if (control != NULL) + { + // + // If no timeout is provided use + // the default. + // + + T_timestamp newTs; + + if (selectTs == NULL) + { + setTimestamp(newTs, control -> PingTimeout); + + selectTs = &newTs; + } + + // + // Use empty masks and only get the + // descriptors set by the proxy. + // + + fd_set readSet; + fd_set writeSet; + + int setFDs; + int errorFDs; + int resultFDs; + + setFDs = 0; + + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + + // + // Run a new loop. If the transport + // is gone avoid sleeping until the + // timeout. + // + + if (NXTransPrepare(&setFDs, &readSet, &writeSet, selectTs) != 0) + { + NXTransSelect(&resultFDs, &errorFDs, &setFDs, &readSet, &writeSet, selectTs); + + NXTransExecute(&resultFDs, &errorFDs, &setFDs, &readSet, &writeSet, selectTs); + } + } + + return (control != NULL); +} + +int NXTransSignal(int signal, int action) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + if (control == NULL) + { + return 0; + } + + if (action == NX_SIGNAL_RAISE) + { + #ifdef TEST + *logofs << "NXTransSignal: Raising signal '" << DumpSignal(signal) + << "' in the proxy handler.\n" << logofs_flush; + #endif + + HandleSignal(signal); + + return 1; + } + else if (signal == NX_SIGNAL_ANY) + { + #ifdef TEST + *logofs << "NXTransSignal: Setting action of all signals to '" + << action << "'.\n" << logofs_flush; + #endif + + for (int i = 0; i < 32; i++) + { + if (CheckSignal(i) == 1) + { + NXTransSignal(i, action); + } + } + + return 1; + } + else if (CheckSignal(signal) == 1) + { + #ifdef TEST + *logofs << "NXTransSignal: Setting action of signal '" + << DumpSignal(signal) << "' to '" << action + << "'.\n" << logofs_flush; + #endif + + if (action == NX_SIGNAL_ENABLE || + action == NX_SIGNAL_FORWARD) + { + InstallSignal(signal, action); + + return 1; + } + else if (action == NX_SIGNAL_DISABLE) + { + RestoreSignal(signal); + + return 1; + } + } + + #ifdef WARNING + *logofs << "NXTransSignal: WARNING! Unable to perform action '" + << action << "' on signal '" << DumpSignal(signal) + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Unable to perform action '" << action + << "' on signal '" << DumpSignal(signal) + << "'.\n"; + + return -1; +} + +int NXTransCongestion(int fd) +{ + if (control != NULL && proxy != NULL) + { + #ifdef DUMP + + int congestion = proxy -> getCongestion(proxyFD); + + *logofs << "NXTransCongestion: Returning " << congestion + << " as current congestion level.\n" << logofs_flush; + + return congestion; + + #endif + + return (proxy -> getCongestion(proxyFD)); + } + + return 0; +} + +int NXTransHandler(int fd, int type, void (*handler)(void *parameter, + int reason), void *parameter) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + switch (type) + { + case NX_HANDLER_FLUSH: + { + flushCallback = handler; + flushParameter = parameter; + + break; + } + case NX_HANDLER_STATISTICS: + { + // + // Reporting of statistics by the agent + // still needs to be implemented. + // + + statisticsCallback = handler; + statisticsParameter = parameter; + + break; + } + default: + { + #ifdef TEST + *logofs << "NXTransHandler: WARNING! Failed to set " + << "the NX callback for event '" << type << "' to '" + << (void *) handler << "' and parameter '" + << parameter << "'.\n" << logofs_flush; + #endif + + return 0; + } + } + + #ifdef TEST + *logofs << "NXTransHandler: Set the NX " + << "callback for event '" << type << "' to '" + << (void *) handler << "' and parameter '" + << parameter << "'.\n" << logofs_flush; + #endif + + return 1; +} + +int NXTransRead(int fd, char *data, int size) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + if (control != NULL && agent != NULL && + fd == agentFD[0]) + { + #ifdef DUMP + *logofs << "NXTransRead: Dequeuing " << size << " bytes " + << "from FD#" << agentFD[0] << ".\n" << logofs_flush; + #endif + + int result = agent -> dequeueData(data, size); + + #ifdef DUMP + + if (result < 0 && EGET() == EAGAIN) + { + *logofs << "NXTransRead: WARNING! Dequeuing from FD#" + << agentFD[0] << " would block.\n" << logofs_flush; + } + else + { + *logofs << "NXTransRead: Dequeued " << result << " bytes " + << "to FD#" << agentFD[0] << ".\n" << logofs_flush; + } + + #endif + + return result; + } + else + { + #ifdef DUMP + *logofs << "NXTransRead: Reading " << size << " bytes " + << "from FD#" << fd << ".\n" << logofs_flush; + #endif + + return read(fd, data, size); + } +} + +int NXTransReadVector(int fd, struct iovec *iovdata, int iovsize) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + if (control != NULL && agent != NULL && + fd == agentFD[0]) + { + #if defined(DUMP) + + if (control -> ProxyStage >= stage_operational && + agent -> localReadable() > 0) + { + *logofs << "NXTransReadVector: WARNING! Agent has data readable.\n" + << logofs_flush; + } + + #endif + + char *base; + + int length; + int result; + + struct iovec *vector = iovdata; + int count = iovsize; + + ESET(0); + + int i = 0; + int total = 0; + + for (; i < count; i++, vector++) + { + length = vector -> iov_len; + base = (char *) vector -> iov_base; + + while (length > 0) + { + #ifdef DUMP + *logofs << "NXTransReadVector: Dequeuing " << length + << " bytes " << "from FD#" << agentFD[0] << ".\n" + << logofs_flush; + #endif + + result = agent -> dequeueData(base, length); + + #ifdef DUMP + + if (result < 0 && EGET() == EAGAIN) + { + *logofs << "NXTransReadVector: WARNING! Dequeuing from FD#" + << agentFD[0] << " would block.\n" << logofs_flush; + } + else + { + *logofs << "NXTransReadVector: Dequeued " << result + << " bytes " << "from FD#" << agentFD[0] << ".\n" + << logofs_flush; + } + + #endif + + if (result < 0 && total == 0) + { + return result; + } + else if (result <= 0) + { + return total; + } + + ESET(0); + + length -= result; + total += result; + base += result; + } + } + + return total; + } + else + { + #ifdef DUMP + *logofs << "NXTransReadVector: Reading vector with " + << iovsize << " elements from FD#" << fd << ".\n" + << logofs_flush; + #endif + + return readv(fd, iovdata, iovsize); + } +} + +int NXTransReadable(int fd, int *readable) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + if (control == NULL || agent == NULL || + fd != agentFD[0]) + { + #ifdef DUMP + + int result = GetBytesReadable(fd, readable); + + if (result == -1) + { + *logofs << "NXTransReadable: Error detected on FD#" + << fd << ".\n" << logofs_flush; + } + else + { + *logofs << "NXTransReadable: Returning " << *readable + << " bytes as readable from FD#" << fd + << ".\n" << logofs_flush; + } + + return result; + + #else + + return GetBytesReadable(fd, readable); + + #endif + } + + int result = agent -> dequeuableData(); + + switch (result) + { + case 0: + { + // + // The client might have enqueued data to our side + // and is now checking for the available events. As + // _XEventsQueued() may omit to call _XSelect(), we + // handle here the new data that is coming from the + // proxy to avoid spinning through this function + // again. + // + + if (proxy != NULL && proxy -> canRead() == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "NXTransReadable: WARNING! Trying to " + << "read to generate new agent data.\n" + << logofs_flush; + #endif + + // + // Set the context as the function + // can cause a cleanup. + // + + if (setjmp(context) == 1) + { + return -1; + } + + if (proxy -> handleRead() < 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "NXTransReadable: Failure reading " + << "messages from proxy FD#" << proxyFD + << ".\n" << logofs_flush; + #endif + + HandleShutdown(); + } + + // + // Call again the routine. By reading + // new control messages from the proxy + // the agent channel may be gone. + // + + return NXTransReadable(fd, readable); + } + + #ifdef DUMP + *logofs << "NXTransReadable: Returning " << 0 + << " bytes as readable from FD#" << fd + << " with result 0.\n" << logofs_flush; + #endif + + *readable = 0; + + return 0; + } + case -1: + { + #ifdef DUMP + *logofs << "NXTransReadable: Returning " << 0 + << " bytes as readable from FD#" << fd + << " with result -1.\n" << logofs_flush; + #endif + + *readable = 0; + + return -1; + } + default: + { + #ifdef DUMP + *logofs << "NXTransReadable: Returning " << result + << " bytes as readable from FD#" << fd + << " with result 0.\n" << logofs_flush; + #endif + + *readable = result; + + return 0; + } + } +} + +int NXTransWrite(int fd, char *data, int size) +{ + // + // Be sure we have a valid log file. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + if (control != NULL && agent != NULL && + fd == agentFD[0]) + { + int result; + + if (proxy != NULL) + { + if (proxy -> canRead(agentFD[1]) == 0) + { + #if defined(DUMP) || defined(TEST) + *logofs << "NXTransWrite: WARNING! Delayed enqueuing to FD#" + << agentFD[0] << " with proxy unable to read.\n" + << logofs_flush; + #endif + + ESET(EAGAIN); + + return -1; + } + + // + // Set the context as the function + // can cause a cleanup. + // + + if (setjmp(context) == 1) + { + return -1; + } + + // + // Don't enqueue the data to the transport + // but let the channel borrow the buffer. + // + + #ifdef DUMP + *logofs << "NXTransWrite: Letting the channel borrow " + << size << " bytes from FD#" << agentFD[0] + << ".\n" << logofs_flush; + #endif + + result = proxy -> handleRead(agentFD[1], data, size); + + if (result == 1) + { + result = size; + } + else + { + if (result == 0) + { + ESET(EAGAIN); + } + else + { + ESET(EPIPE); + } + + result = -1; + } + } + else + { + // + // We don't have a proxy connection, yet. + // Enqueue the data to the agent transport. + // + + #ifdef DUMP + *logofs << "NXTransWrite: Enqueuing " << size << " bytes " + << "to FD#" << agentFD[0] << ".\n" << logofs_flush; + #endif + + result = agent -> enqueueData(data, size); + } + + #ifdef DUMP + + if (result < 0) + { + if (EGET() == EAGAIN) + { + *logofs << "NXTransWrite: WARNING! Enqueuing to FD#" + << agentFD[0] << " would block.\n" + << logofs_flush; + } + else + { + *logofs << "NXTransWrite: WARNING! Error enqueuing to FD#" + << agentFD[0] << ".\n" << logofs_flush; + } + } + else + { + *logofs << "NXTransWrite: Enqueued " << result << " bytes " + << "to FD#" << agentFD[0] << ".\n" << logofs_flush; + } + + #endif + + return result; + } + else + { + #ifdef DUMP + *logofs << "NXTransWrite: Writing " << size << " bytes " + << "to FD#" << fd << ".\n" << logofs_flush; + #endif + + return write(fd, data, size); + } +} + +int NXTransWriteVector(int fd, struct iovec *iovdata, int iovsize) +{ + // + // Be sure we have a valid log file and a + // jump context because we will later call + // functions that can perform a cleanup. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + int result = 0; + + if (control != NULL && agent != NULL && + fd == agentFD[0]) + { + // + // See the comment in NXTransWrite(). + // + + if (proxy != NULL) + { + if (proxy -> canRead(agentFD[1]) == 0) + { + #if defined(DUMP) || defined(TEST) + *logofs << "NXTransWriteVector: WARNING! Delayed enqueuing to FD#" + << agentFD[0] << " with proxy unable to read.\n" + << logofs_flush; + #endif + + ESET(EAGAIN); + + return -1; + } + } + + // + // Set the context as the function + // can cause a cleanup. + // + + if (setjmp(context) == 1) + { + return -1; + } + + char *base; + + int length; + + struct iovec *vector = iovdata; + int count = iovsize; + + ESET(0); + + int i = 0; + int total = 0; + + for (; i < count; i++, vector++) + { + length = vector -> iov_len; + base = (char *) vector -> iov_base; + + while (length > 0) + { + if (proxy != NULL) + { + // + // Don't enqueue the data to the transport + // but let the channel borrow the buffer. + // + + #ifdef DUMP + *logofs << "NXTransWriteVector: Letting the channel borrow " + << length << " bytes from FD#" << agentFD[0] + << ".\n" << logofs_flush; + #endif + + result = proxy -> handleRead(agentFD[1], base, length); + + if (result == 1) + { + result = length; + } + else + { + if (result == 0) + { + ESET(EAGAIN); + } + else + { + ESET(EPIPE); + } + + result = -1; + } + } + else + { + // + // We don't have a proxy connection, yet. + // Enqueue the data to the agent transport. + // + + #ifdef DUMP + *logofs << "NXTransWriteVector: Enqueuing " << length + << " bytes " << "to FD#" << agentFD[0] << ".\n" + << logofs_flush; + #endif + + result = agent -> enqueueData(base, length); + } + + #ifdef DUMP + + if (result < 0) + { + if (EGET() == EAGAIN) + { + *logofs << "NXTransWriteVector: WARNING! Enqueuing to FD#" + << agentFD[0] << " would block.\n" + << logofs_flush; + } + else + { + *logofs << "NXTransWriteVector: WARNING! Error enqueuing to FD#" + << agentFD[0] << ".\n" << logofs_flush; + } + } + else + { + *logofs << "NXTransWriteVector: Enqueued " << result + << " bytes " << "to FD#" << agentFD[0] << ".\n" + << logofs_flush; + } + + #endif + + if (result < 0 && total == 0) + { + return result; + } + else if (result <= 0) + { + return total; + } + + ESET(0); + + length -= result; + total += result; + base += result; + } + } + + return total; + } + else + { + #ifdef DUMP + *logofs << "NXTransWriteVector: Writing vector with " + << iovsize << " elements to FD#" << fd << ".\n" + << logofs_flush; + #endif + + return writev(fd, iovdata, iovsize); + } +} + +int NXTransPolicy(int fd, int type) +{ + if (control != NULL) + { + if (usePolicy == -1) + { + #if defined(TEST) || defined(INFO) + *logofs << "NXTransPolicy: Setting flush policy on " + << "proxy FD#" << proxyFD << " to '" + << DumpPolicy(type == NX_POLICY_DEFERRED ? + policy_deferred : policy_immediate) + << "'.\n" << logofs_flush; + #endif + + control -> FlushPolicy = (type == NX_POLICY_DEFERRED ? + policy_deferred : policy_immediate); + + if (proxy != NULL) + { + proxy -> handleFlush(); + } + + return 1; + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "NXTransPolicy: Ignoring the agent " + << "setting with user policy set to '" + << DumpPolicy(control -> FlushPolicy) + << "'.\n" << logofs_flush; + #endif + + return 0; + } + } + + return 0; +} + +int NXTransFlushable(int fd) +{ + if (proxy == NULL || agent == NULL || + fd != agentFD[0]) + { + #ifdef DUMP + *logofs << "NXTransFlushable: Returning 0 bytes as " + << "flushable for unrecognized FD#" << fd + << ".\n" << logofs_flush; + #endif + + return 0; + } + else + { + #if defined(DUMP) || defined(INFO) + *logofs << "NXTransFlushable: Returning " << proxy -> + getFlushable(proxyFD) << " as bytes flushable on " + << "proxy FD#" << proxyFD << ".\n" + << logofs_flush; + #endif + + return proxy -> getFlushable(proxyFD); + } +} + +int NXTransFlush(int fd) +{ + if (proxy != NULL) + { + #if defined(TEST) || defined(INFO) + *logofs << "NXTransFlush: Requesting an immediate flush of " + << "proxy FD#" << proxyFD << ".\n" + << logofs_flush; + #endif + + return proxy -> handleFlush(); + } + + return 0; +} + +int NXTransChannel(int fd, int channelFd, int type) +{ + if (proxy != NULL) + { + // + // Set the context as the function + // can cause a cleanup. + // + + if (setjmp(context) == 1) + { + return -1; + } + + #if defined(TEST) || defined(INFO) + *logofs << "NXTransChannel: Going to create a new channel " + << "with type '" << type << "' on FD#" << channelFd + << ".\n" << logofs_flush; + #endif + + int result = -1; + + switch (type) + { + case NX_CHANNEL_X11: + { + if (useUnixSocket == 1 || useTcpSocket == 1 || + useAgentSocket == 1 || useAuxSocket == 1) + { + result = proxy -> handleNewConnection(channel_x11, channelFd); + } + + break; + } + case NX_CHANNEL_CUPS: + { + if (useCupsSocket == 1) + { + result = proxy -> handleNewConnection(channel_cups, channelFd); + } + + break; + } + case NX_CHANNEL_SMB: + { + if (useSmbSocket == 1) + { + result = proxy -> handleNewConnection(channel_smb, channelFd); + } + + break; + } + case NX_CHANNEL_MEDIA: + { + if (useMediaSocket == 1) + { + result = proxy -> handleNewConnection(channel_media, channelFd); + } + + break; + } + case NX_CHANNEL_HTTP: + { + if (useHttpSocket == 1) + { + result = proxy -> handleNewConnection(channel_http, channelFd); + } + + break; + } + case NX_CHANNEL_FONT: + { + if (useFontSocket == 1) + { + result = proxy -> handleNewConnection(channel_font, channelFd); + } + + break; + } + case NX_CHANNEL_SLAVE: + { + if (useSlaveSocket == 1) + { + result = proxy -> handleNewConnection(channel_slave, channelFd); + } + + break; + } + default: + { + #ifdef WARNING + *logofs << "NXTransChannel: WARNING! Unrecognized channel " + << "type '" << type << "'.\n" << logofs_flush; + #endif + + break; + } + } + + #ifdef WARNING + + if (result != 1) + { + *logofs << "NXTransChannel: WARNING! Could not create the " + << "new channel with type '" << type << "' on FD#" + << channelFd << ".\n" << logofs_flush; + } + + #endif + + return result; + } + + return 0; +} + +const char *NXTransFile(int type) +{ + char *name = NULL; + + switch (type) + { + case NX_FILE_SESSION: + { + name = sessionFileName; + + break; + } + case NX_FILE_ERRORS: + { + name = errorsFileName; + + break; + } + case NX_FILE_OPTIONS: + { + name = optionsFileName; + + break; + } + case NX_FILE_STATS: + { + name = statsFileName; + + break; + } + } + + if (name != NULL && *name != '\0') + { + return name; + } + + return NULL; +} + +long NXTransTime() +{ + static T_timestamp last = getTimestamp(); + + T_timestamp now = getTimestamp(); + + long diff = diffTimestamp(last, now); + + last = now; + + return diff; +} + +int NXTransAlert(int code, int local) +{ + if (proxy != NULL) + { + #if defined(DUMP) || defined(INFO) + *logofs << "NXTransAlert: Requesting a NX dialog with code " + << code << " and local " << local << ".\n" + << logofs_flush; + #endif + + if (local == 0) + { + // + // Set the context as the function + // can cause a cleanup. + // + + if (setjmp(context) == 1) + { + return -1; + } + + proxy -> handleAlert(code); + } + else + { + // + // Show the alert at the next loop. + // + + HandleAlert(code, local); + } + + return 1; + } + #if defined(DUMP) || defined(INFO) + else + { + if (logofs == NULL) + { + logofs = &cerr; + } + + *logofs << "NXTransAlert: Can't request an alert without " + << "a valid NX transport.\n" << logofs_flush; + } + #endif + + return 0; +} + +// +// Prepare the file sets and the timeout +// for a later execution of the select(). +// + +int NXTransPrepare(int *setFDs, fd_set *readSet, + fd_set *writeSet, struct timeval *selectTs) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + // + // Control is NULL if the NX transport was + // reset or was never created. If control + // is valid then prepare to jump back when + // the transport is destroyed. + // + + if (control == NULL || setjmp(context) == 1) + { + return 0; + } + + #if defined(TEST) || defined(INFO) + *logofs << "\nNXTransPrepare: Going to prepare the NX transport.\n" + << logofs_flush; + #endif + + if (control -> ProxyStage < stage_operational) + { + handleNegotiationInLoop(*setFDs, *readSet, *writeSet, *selectTs); + } + else + { + #if defined(TEST) || defined(INFO) + + if (isTimestamp(*selectTs) == 0) + { + *logofs << "Loop: WARNING! Preparing the select with requested " + << "timeout of " << selectTs -> tv_sec << " S and " + << (double) selectTs -> tv_usec / 1000 << " Ms.\n" + << logofs_flush; + } + else + { + *logofs << "Loop: Preparing the select with requested " + << "timeout of " << selectTs -> tv_sec << " S and " + << (double) selectTs -> tv_usec / 1000 << " Ms.\n" + << logofs_flush; + } + + #endif + + // + // Set descriptors of listening sockets. + // + + handleSetListenersInLoop(*readSet, *setFDs); + + // + // Set descriptors of both proxy and X + // connections. + // + + handleSetReadInLoop(*readSet, *setFDs, *selectTs); + + // + // Find out which file descriptors have + // data to write. + // + + handleSetWriteInLoop(*writeSet, *setFDs, *selectTs); + } + + // + // Prepare the masks for handling the memory- + // to-memory transport. This is required even + // during session negotiation. + // + + if (agent != NULL) + { + handleSetAgentInLoop(*setFDs, *readSet, *writeSet, *selectTs); + } + + // + // Register time spent handling messages. + // + + nowTs = getNewTimestamp(); + + diffTs = diffTimestamp(startTs, nowTs); + + #ifdef TEST + *logofs << "Loop: Mark - 0 - at " << strMsTimestamp() + << " with " << diffTs << " Ms elapsed.\n" + << logofs_flush; + #endif + + // + // TODO: Should add the read time in two + // parts otherwise the limits are checked + // before the counters are updated with + // time spent in the last loop. + // + + if (control -> ProxyStage >= stage_operational) + { + statistics -> addReadTime(diffTs); + } + + startTs = nowTs; + + #ifdef DEBUG + *logofs << "Loop: New timestamp is " << strMsTimestamp(startTs) + << ".\n" << logofs_flush; + #endif + + return 1; +} + +// +// Let's say that we call select() to find out +// if any of the handled descriptors has data, +// but actually things are a bit more complex +// than that. +// + +int NXTransSelect(int *resultFDs, int *errorFDs, int *setFDs, fd_set *readSet, + fd_set *writeSet, struct timeval *selectTs) +{ + #ifdef TIME + + static T_timestamp lastTs; + + #endif + + if (logofs == NULL) + { + logofs = &cerr; + } + + // + // Control is NULL if the NX transport was + // reset or never created. If control is + // valid then prepare for jumping back in + // the case of an error. + // + + if (control == NULL || setjmp(context) == 1) + { + *resultFDs = select(*setFDs, readSet, writeSet, NULL, selectTs); + + *errorFDs = errno; + + return 0; + } + + #if defined(TEST) || defined(INFO) + *logofs << "\nNXTransSelect: Going to select the NX descriptors.\n" + << logofs_flush; + #endif + + #if defined(TEST) || defined(INFO) + + handleCheckSelectInLoop(*setFDs, *readSet, *writeSet, *selectTs); + + #endif + + #ifdef TIME + + diffTs = diffTimestamp(lastTs, getNewTimestamp()); + + if (diffTs > 20) + { + *logofs << "Loop: TIME! Spent " << diffTs + << " Ms handling messages for proxy FD#" + << proxyFD << ".\n" << logofs_flush; + } + + lastTs = getNewTimestamp(); + + #endif + + #if defined(TEST) || defined(INFO) + + if (isTimestamp(*selectTs) == 0) + { + *logofs << "Loop: WARNING! Executing the select with requested " + << "timeout of " << selectTs -> tv_sec << " S and " + << (double) selectTs -> tv_usec / 1000 << " Ms.\n" + << logofs_flush; + } + else if (proxy != NULL && proxy -> getFlushable(proxyFD) > 0) + { + *logofs << "Loop: WARNING! Proxy FD#" << proxyFD + << " has " << proxy -> getFlushable(proxyFD) + << " bytes to write but timeout is " + << selectTs -> tv_sec << " S and " + << selectTs -> tv_usec / 1000 << " Ms.\n" + << logofs_flush; + } + + #endif + + // + // Wait for the selected sockets + // or the timeout. + // + + ESET(0); + + *resultFDs = select(*setFDs, readSet, writeSet, NULL, selectTs); + + *errorFDs = EGET(); + + #ifdef TIME + + diffTs = diffTimestamp(lastTs, getNewTimestamp()); + + if (diffTs > 100) + { + *logofs << "Loop: TIME! Spent " << diffTs + << " Ms waiting for new data for proxy FD#" + << proxyFD << ".\n" << logofs_flush; + } + + lastTs = getNewTimestamp(); + + #endif + + // + // Check the result of the select. + // + + #if defined(TEST) || defined(INFO) + + handleCheckResultInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs, startTs); + + #endif + + // + // Get time spent in select. The accouting is done + // in milliseconds. This is a real problem on fast + // machines where each loop is unlikely to take + // more than 500 us, so consider that the results + // can be inaccurate. + // + + nowTs = getNewTimestamp(); + + diffTs = diffTimestamp(startTs, nowTs); + + #ifdef TEST + *logofs << "Loop: Out of select after " << diffTs << " Ms " + << "at " << strMsTimestamp(nowTs) << " with result " + << *resultFDs << ".\n" << logofs_flush; + #endif + + startTs = nowTs; + + #ifdef DEBUG + *logofs << "Loop: New timestamp is " << strMsTimestamp(startTs) + << ".\n" << logofs_flush; + #endif + + if (control -> ProxyStage >= stage_operational) + { + statistics -> addIdleTime(diffTs); + } + + if (*resultFDs < 0) + { + // + // Check if the call was interrupted or if any of the + // managed descriptors has become invalid. This can + // happen to the X11 code, before the descriptor is + // removed from the managed set. + // + + #ifdef __sun + + if (*errorFDs == EINTR || *errorFDs == EBADF || + *errorFDs == EINVAL) + + #else + + if (*errorFDs == EINTR || *errorFDs == EBADF) + + #endif + + { + #ifdef TEST + + if (*errorFDs == EINTR) + { + *logofs << "Loop: Select failed due to EINTR error.\n" + << logofs_flush; + } + else + { + *logofs << "Loop: WARNING! Call to select failed. Error is " + << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + } + + #endif + } + else + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to select failed. Error is " + << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Call to select failed. Error is " + << EGET() << " '" << ESTR() << "'.\n"; + + HandleCleanup(); + } + } + + return 1; +} + +// +// Perform the required actions on all +// the descriptors having I/O pending. +// + +int NXTransExecute(int *resultFDs, int *errorFDs, int *setFDs, fd_set *readSet, + fd_set *writeSet, struct timeval *selectTs) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + // + // Control is NULL if the NX transport was + // reset or never created. If control is + // valid then prepare for jumping back in + // the case of an error. + // + + if (control == NULL || setjmp(context) == 1) + { + return 0; + } + + #if defined(TEST) || defined(INFO) + *logofs << "\nNXTransExecute: Going to execute I/O on the NX descriptors.\n" + << logofs_flush; + #endif + + if (control -> ProxyStage >= stage_operational) + { + // + // Check if I/O is possible on the proxy and + // local agent descriptors. + // + + if (agent != NULL) + { + handleAgentInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs); + } + + #ifdef TEST + *logofs << "Loop: Mark - 1 - at " << strMsTimestamp() + << " with " << diffTimestamp(startTs, getTimestamp()) + << " Ms elapsed.\n" << logofs_flush; + #endif + + // + // Rotate the channel that will be handled + // first. + // + + handleRotateInLoop(); + + // + // Flush any data on newly writable sockets. + // + + handleWritableInLoop(*resultFDs, *writeSet); + + #ifdef TEST + *logofs << "Loop: Mark - 2 - at " << strMsTimestamp() + << " with " << diffTimestamp(startTs, getTimestamp()) + << " Ms elapsed.\n" << logofs_flush; + #endif + + // + // Check if any socket has become readable. + // + + handleReadableInLoop(*resultFDs, *readSet); + + #ifdef TEST + *logofs << "Loop: Mark - 3 - at " << strMsTimestamp() + << " with " << diffTimestamp(startTs, getTimestamp()) + << " Ms elapsed.\n" << logofs_flush; + #endif + + // + // Handle the scheduled events on channels. + // + // - Restart, if possible, any client that was + // put to sleep. + // + // - Check if there are pointer motion events to + // flush. This applies only to X server side. + // + // - Check if any channel has exited the conges- + // tion state. + // + // - Check if there are images that are currently + // being streamed. + // + + handleEventsInLoop(); + + #ifdef TEST + *logofs << "Loop: Mark - 4 - at " << strMsTimestamp() + << " with " << diffTimestamp(startTs, getTimestamp()) + << " Ms elapsed.\n" << logofs_flush; + #endif + + // + // Check if user sent a signal to produce + // statistics. + // + + handleStatisticsInLoop(); + + // + // We may have flushed the proxy link or + // handled data coming from the remote. + // Post-process the masks and set the + // selected agent descriptors as ready. + // + + if (agent != NULL) + { + handleAgentLateInLoop(*resultFDs, *errorFDs, *setFDs, *readSet, *writeSet, *selectTs); + } + + #ifdef TEST + *logofs << "Loop: Mark - 5 - at " << strMsTimestamp() + << " with " << diffTimestamp(startTs, getTimestamp()) + << " Ms elapsed.\n" << logofs_flush; + #endif + + // + // Check if there is any data to flush. + // Agents should flush the proxy link + // explicitly. + // + + handleFlushInLoop(); + + #ifdef TEST + *logofs << "Loop: Mark - 6 - at " << strMsTimestamp() + << " with " << diffTimestamp(startTs, getTimestamp()) + << " Ms elapsed.\n" << logofs_flush; + #endif + } + + // + // Check if we have an alert to show. + // + + handleAlertInLoop(); + + if (control -> ProxyStage >= stage_operational) + { + // + // Check if it's time to give up. + // + + handleCheckSessionInLoop(); + + // + // Check if local proxy is consuming + // too many resources. + // + + handleCheckBitrateInLoop(); + + // + // Check coherency of internal state. + // + + #if defined(TEST) || defined(INFO) + + handleCheckStateInLoop(*setFDs); + + #endif + + #ifdef TEST + *logofs << "Loop: Mark - 7 - at " << strMsTimestamp() + << " with " << diffTimestamp(startTs, getTimestamp()) + << " Ms elapsed.\n" << logofs_flush; + #endif + } + + // + // Truncate the logs if needed. + // + + handleLogReopenInLoop(logsTs, nowTs); + + return 1; +} + +// +// Initialize the connection parameters and +// prepare for negotiating the link with the +// remote proxy. +// + +int InitBeforeNegotiation() +{ + // + // Disable limits on core dumps. + // + + SetCore(); + + // + // Install the signal handlers. + // + + InstallSignals(); + + // + // Track how much time we spent in initialization. + // + + nowTs = getNewTimestamp(); + + startTs = nowTs; + initTs = nowTs; + + #ifdef TEST + *logofs << "Loop: INIT! Taking mark for initialization at " + << strMsTimestamp(initTs) << ".\n" + << logofs_flush; + #endif + + // + // If not explicitly specified, determine if local + // mode is client or server according to parameters + // provided so far. + // + + if (WE_SET_PROXY_MODE == 0) + { + cerr << "Error" << ": Please specify either the -C or -S option.\n"; + + HandleCleanup(); + } + + // + // Start a watchdog. If initialization cannot + // be completed before timeout, then clean up + // everything and exit. + // + + if (control -> ProxyMode == proxy_client) + { + #ifdef TEST + *logofs << "Loop: Starting watchdog process with timeout of " + << control -> InitTimeout / 1000 << " seconds.\n" + << logofs_flush; + #endif + + lastWatchdog = NXTransWatchdog(control -> InitTimeout); + + if (IsFailed(lastWatchdog)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't start the NX watchdog process.\n" + << logofs_flush; + #endif + + SetNotRunning(lastWatchdog); + } + #ifdef TEST + else + { + *logofs << "Loop: Watchdog started with pid '" + << lastWatchdog << "'.\n" << logofs_flush; + } + #endif + } + + // + // Print preliminary info. + // + + PrintProcessInfo(); + + // + // Set cups, multimedia and other + // auxiliary ports. + // + + SetPorts(); + + // + // Increase the number of maximum open + // file descriptors for this process. + // + + SetDescriptors(); + + // + // Set local endianess. + // + + unsigned int test = 1; + + setHostBigEndian(*((unsigned char *) (&test)) == 0); + + #ifdef TEST + *logofs << "Loop: Local host is " + << (hostBigEndian() ? "big endian" : "little endian") + << ".\n" << logofs_flush; + #endif + + if (control -> ProxyMode == proxy_client) + { + // + // Listen on sockets that mimic an X display to + // which X clients will be able to connect (e.g. + // unix:8 and/or localhost:8). + // + + if (useTcpSocket == 1) + { + SetupTcpSocket(); + } + + if (useUnixSocket == 1) + { + SetupUnixSocket(); + } + } + else + { + // + // Don't listen for X connections. + // + + useUnixSocket = 0; + useTcpSocket = 0; + useAgentSocket = 0; + + // + // Get ready to open the local display. + // + + SetupDisplaySocket(xServerAddrFamily, xServerAddr, xServerAddrLength); + } + + // + // If we are the NX server-side proxy we need to + // complete our initializazion. We will mandate + // our parameters at the time the NX client will + // connect. + // + + if (control -> ProxyMode == proxy_client) + { + SetParameters(); + } + + return 1; +} + +int SetupProxyConnection() +{ + + if (proxyFD == -1) + { + + char *socketUri = NULL; + + // Let's make sure, the default value for listenSocket is properly set. Doing this + // here, because we have to make sure that we call it after the connectSocket + // declaration is really really complete. + + if (listenSocket.disabled() && connectSocket.disabled()) + { + char listenPortValue[20] = { 0 }; + sprintf(listenPortValue, "%ld", (long)(proxyPort + DEFAULT_NX_PROXY_PORT_OFFSET)); + + SetAndValidateChannelEndPointArg("local", "listen", listenPortValue, listenSocket); + } + + #ifdef TEST + connectSocket.getSpec(&socketUri); + *logofs << "Loop: connectSocket is "<< ( connectSocket.enabled() ? "enabled" : "disabled") << ". " + << "The socket URI is '"<< ( socketUri != NULL ? socketUri : "") << "'.\n" << logofs_flush; + listenSocket.getSpec(&socketUri); + *logofs << "Loop: listenSocket is "<< ( listenSocket.enabled() ? "enabled" : "disabled") << ". " + << "The socket URI is '"<< ( socketUri != NULL ? socketUri : "") << "'.\n" << logofs_flush; + free(socketUri); + socketUri = NULL; + #endif + + if (WE_INITIATE_CONNECTION) + { + if (connectSocket.getSpec(&socketUri)) + { + #ifdef TEST + *logofs << "Loop: Going to connect to '" << socketUri + << "'.\n" << logofs_flush; + #endif + free(socketUri); + + proxyFD = ConnectToRemote(connectSocket); + + #ifdef TEST + *logofs << "Loop: Connected to remote proxy on FD#" + << proxyFD << ".\n" << logofs_flush; + #endif + + cerr << "Info" << ": Connected to remote proxy on FD#" + << proxyFD << ".\n"; + } + } + else + { + + if (listenSocket.isTCPSocket() && (listenSocket.getTCPPort() < 0)) + { + listenSocket.setSpec(DEFAULT_NX_PROXY_PORT_OFFSET + proxyPort); + } + + if (listenSocket.getSpec(&socketUri)) + { + #ifdef TEST + *logofs << "Loop: Going to wait for connection at '" + << socketUri << "'.\n" << logofs_flush; + #endif + free(socketUri); + + proxyFD = WaitForRemote(listenSocket); + + #ifdef TEST + if (WE_LISTEN_FORWARDER) + { + *logofs << "Loop: Connected to remote forwarder on FD#" + << proxyFD << ".\n" << logofs_flush; + } + else + { + *logofs << "Loop: Connected to remote proxy on FD#" + << proxyFD << ".\n" << logofs_flush; + } + #endif + + } + } + } + #ifdef TEST + else + { + *logofs << "Loop: Using the inherited connection on FD#" + << proxyFD << ".\n" << logofs_flush; + } + #endif + + // + // Set TCP_NODELAY on proxy descriptor + // to reduce startup time. Option will + // later be disabled if needed. + // + // either listenSocket or connectSocket is used here... + + if(listenSocket.isTCPSocket() || connectSocket.isTCPSocket()) + + SetNoDelay(proxyFD, 1); + + // + // We need non-blocking input since the + // negotiation phase. + // + + SetNonBlocking(proxyFD, 1); + + return 1; +} + +// +// Create the required proxy and channel classes +// and get ready for handling the encoded traffic. +// + +int InitAfterNegotiation() +{ + #ifdef TEST + *logofs << "Loop: Connection with remote proxy completed.\n" + << logofs_flush; + #endif + + cerr << "Info" << ": Connection with remote proxy completed.\n" + << logofs_flush; + + // + // If we are the server proxy we completed + // our initializazion phase according to + // the values provided by the client side. + // + + if (control -> ProxyMode == proxy_server) + { + SetParameters(); + } + + // + // Set up the listeners for the additional + // services. + // + + SetupServiceSockets(); + + // + // Create the proxy class and the statistics + // repository and pass all the configuration + // data we negotiated with the remote peer. + // + + SetupProxyInstance(); + + // + // We completed both parsing of user's parameters + // and handlshaking with remote proxy. Now print + // a brief summary including the most significant + // control values. + // + + PrintConnectionInfo(); + + // + // Cancel the initialization watchdog. + // + + if (IsRunning(lastWatchdog)) + { + KillProcess(lastWatchdog, "watchdog", SIGTERM, 1); + + SetNotRunning(lastWatchdog); + + lastSignal = 0; + } + + // + // Start the house-keeper process. It will + // remove the oldest persistent caches, if + // the amount of storage exceed the limits + // set by the user. + // + + StartKeeper(); + + // + // Set the log size check timestamp. + // + + nowTs = getNewTimestamp(); + + logsTs = nowTs; + + // + // TODO: Due to the way the new NX transport is working, + // the accounting of time spent handling messages must + // be rewritten. In particular, at the moment it only + // shows the time spent encoding and decoding messages + // in the main loop, after executing a select. It doesn't + // take into account the time spent in the NXTrans* calls + // where messages can be encoded and decoded implicitly, + // on demand of the agent. When the agent transport is + // in use, these calls constitute the vast majority of + // the encoding activity. The result is that the number + // of KB encoded per second shown by the proxy statistics + // is actually much lower than the real throughput gene- + // rated by the proxy. + // + + #ifdef TEST + *logofs << "Loop: INIT! Completed initialization at " + << strMsTimestamp(nowTs) << " with " + << diffTimestamp(initTs, nowTs) << " Ms " + << "since the init mark.\n" << logofs_flush; + #endif + + initTs = getNewTimestamp(); + + // + // We can now start handling binary data from + // our peer proxy. + // + + if (agent == NULL) + { + cerr << "Session" << ": Session started at '" + << strTimestamp() << "'.\n"; + } + + return 1; +} + +int SetMode(int mode) +{ + // + // Set the local proxy mode. + // + + if (control -> ProxyMode == proxy_undefined) + { + if (mode == NX_MODE_CLIENT) + { + #ifdef TEST + *logofs << "Loop: INIT! Initializing with mode " + << "NX_MODE_CLIENT at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + control -> ProxyMode = proxy_client; + } + else if (mode == NX_MODE_SERVER) + { + #ifdef TEST + *logofs << "Loop: INIT! Initializing with mode " + << "NX_MODE_SERVER at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + control -> ProxyMode = proxy_server; + } + else + { + cerr << "Error" << ": Please specify either " + << "the -C or -S option.\n"; + + HandleCleanup(); + } + } + + return 1; +} + +int SetupProxyInstance() +{ + if (control -> ProxyMode == proxy_client) + { + proxy = new ClientProxy(proxyFD); + } + else + { + proxy = new ServerProxy(proxyFD); + } + + if (proxy == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error creating the NX proxy.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error creating the NX proxy.\n"; + + HandleCleanup(); + } + + // + // Create the statistics repository. + // + + statistics = new Statistics(proxy); + + if (statistics == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error creating the NX statistics.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error creating the NX statistics.\n"; + + HandleCleanup(); + } + + // + // If user gave us a proxy cookie than create the + // X11 authorization repository and find the real + // cookie to be used for our X display. + // + + SetupAuthInstance(); + + // + // Reset the static members in channels. + // + + proxy -> handleChannelConfiguration(); + + // + // Inform the proxies about the ports where they + // will have to forward the network connections. + // + + proxy -> handleDisplayConfiguration(displayHost, xServerAddrFamily, + xServerAddr, xServerAddrLength); + + proxy -> handlePortConfiguration(cupsPort, smbPort, mediaPort, + httpPort, fontPort); + + // + // We handed over the sockaddr structure we + // created when we set up the display socket + // to the proxy. + // + + xServerAddr = NULL; + + // + // Set socket options on proxy link, then propagate link + // configuration to proxy. This includes translating some + // control parameters in 'local' and 'remote'. Finally + // adjust cache parameters according to pack method and + // session type selected by user. + // + + if (proxy -> handleSocketConfiguration() < 0 || + proxy -> handleLinkConfiguration() < 0 || + proxy -> handleCacheConfiguration() < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error configuring the NX transport.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error configuring the NX transport.\n"; + + HandleCleanup(); + } + + // + // Load the message stores from the persistent + // cache. + // + + proxy -> handleLoad(load_if_first); + + // + // Inform the proxy that from now on it can + // start handling the encoded data. + // + + proxy -> setOperational(); + + // + // Are we going to use an internal IPC connection + // with an agent? In this case create the channel + // by using the socket descriptor provided by the + // caller at the proxy initialization. + // + + SetupAgentInstance(); + + // + // Check if we need to verify the existence of + // a matching client cache at shutdown. + // + + #ifdef MATCH + + control -> PersistentCacheCheckOnShutdown = 1; + + #endif + + // + // Flush any data produced so far. + // + + proxy -> handleFlush(); + + #if defined(TEST) || defined(INFO) + + if (proxy -> getFlushable(proxyFD) > 0) + { + *logofs << "Loop: WARNING! Proxy FD#" << proxyFD << " has data " + << "to flush after setup of the NX transport.\n" + << logofs_flush; + } + + #endif + + return 1; +} + +int SetupAuthInstance() +{ + // + // If user gave us a proxy cookie, then create the + // X11 authorization repository and find the real + // cookie to be used for our X display. + // + + if (control -> ProxyMode == proxy_server) + { + if (authCookie != NULL && *authCookie != '\0') + { + if (useLaunchdSocket == 1) + { + // + // If we are going to retrieve the X11 autho- + // rization through the launchd service, make + // a connection to its socket to trigger the + // X server starting. + // + + sockaddr_un launchdAddrUnix; + + unsigned int launchdAddrLength = sizeof(sockaddr_un); + + int launchdAddrFamily = AF_UNIX; + + launchdAddrUnix.sun_family = AF_UNIX; + + const int launchdAddrNameLength = 108; + + int success = -1; + + strncpy(launchdAddrUnix.sun_path, displayHost, launchdAddrNameLength); + + *(launchdAddrUnix.sun_path + launchdAddrNameLength - 1) = '\0'; + + #ifdef TEST + *logofs << "Loop: Connecting to launchd service " + << "on Unix port '" << displayHost << "'.\n" << logofs_flush; + #endif + + int launchdFd = socket(launchdAddrFamily, SOCK_STREAM, PF_UNSPEC); + + if (launchdFd < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to socket failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + } + else if ((success = connect(launchdFd, (sockaddr *) &launchdAddrUnix, launchdAddrLength)) < 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Connection to launchd service " + << "on Unix port '" << displayHost << "' failed " + << "with error " << EGET() << ", '" << ESTR() << "'.\n" + << logofs_flush; + #endif + } + + if (launchdFd >= 0) + { + close(launchdFd); + } + + // + // The real cookie will not be available + // until the X server starts. Query for the + // cookie in a loop, unless the connection + // to the launchd service failed. + // + + int attempts = (success < 0 ? 1 : 10); + + for (int i = 0; i < attempts; i++) + { + delete auth; + + auth = new Auth(displayHost, authCookie); + + if (auth != NULL && auth -> isFake() == 1) + { + usleep(200000); + + continue; + } + + break; + } + } + else + { + auth = new Auth(displayHost, authCookie); + } + + if (auth == NULL || auth -> isValid() != 1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error creating the X authorization.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error creating the X authorization.\n"; + + HandleCleanup(); + } + else if (auth -> isFake() == 1) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Could not retrieve the X server " + << "authentication cookie.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Failed to read data from the X " + << "auth command.\n"; + + cerr << "Warning" << ": Generated a fake cookie for X " + << "authentication.\n"; + } + } + else + { + #ifdef TEST + *logofs << "Loop: No proxy cookie was provided for " + << "authentication.\n" << logofs_flush; + #endif + + cerr << "Info" << ": No proxy cookie was provided for " + << "authentication.\n"; + + #ifdef TEST + *logofs << "Loop: Forwarding the real X authorization " + << "cookie.\n" << logofs_flush; + #endif + + cerr << "Info" << ": Forwarding the real X authorization " + << "cookie.\n"; + } + } + + return 1; +} + +int SetupAgentInstance() +{ + if (control -> ProxyMode == proxy_client && + useAgentSocket == 1) + { + // + // This will temporarily disable signals to safely + // load the cache, then will send a control packet + // to the remote end, telling that cache has to be + // loaded, so it's important that proxy is already + // set in operational state. + // + + int result; + + if (agent != NULL) + { + result = proxy -> handleNewAgentConnection(agent); + } + else + { + result = proxy -> handleNewConnection(channel_x11, agentFD[1]); + } + + if (result < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error creating the NX agent connection.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error creating the NX agent connection.\n"; + + HandleCleanup(); + } + } + + return 1; +} + +int SetupTcpSocket() +{ + // + // Open TCP socket emulating local display. + // + + return ListenConnectionTCP((loopbackBind ? "localhost" : "*"), X_TCP_PORT + proxyPort, "X11"); +} + +int SetupUnixSocket() +{ + // + // Open UNIX domain socket for display. + // + + if (!control->TempPath) { + #ifdef PANIC + *logofs << "Loop: PANIC! Temporal path is null.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Temporal path is null.\n"; + HandleCleanup(); + } + + unsigned int required = snprintf(unixSocketName, DEFAULT_STRING_LENGTH, "%s/.X11-unix", control->TempPath); + if (required < sizeof(unixSocketName)) { + + // No need to execute the following actions conditionally + mkdir(unixSocketName, (0777 | S_ISVTX)); + chmod(unixSocketName, (0777 | S_ISVTX)); + + required = snprintf(unixSocketName, DEFAULT_STRING_LENGTH, "%s/.X11-unix/X%d", control->TempPath, proxyPort); + if (required < sizeof(unixSocketName)) { + + unixFD = ListenConnectionUnix(unixSocketName, "x11"); + if (unixFD >= 0) + chmod(unixSocketName, 0777); + return unixFD; + } + } + + unixSocketName[0] = '\0'; // Just in case! + + #ifdef PANIC + *logofs << "Loop: PANIC! path for unix socket is too long.\n" << logofs_flush; + #endif + + cerr << "Error" << ": path for Unix socket is too long.\n"; + HandleCleanup(); +} + +// +// The following is a dumb copy-paste. The +// nxcompsh library should offer a better +// implementation. +// + +int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr, + unsigned int &xServerAddrLength) +{ + xServerAddrFamily = AF_INET; + xServerAddr = NULL; + xServerAddrLength = 0; + + char *display; + + if (*displayHost == '\0') + { + // + // Assume DISPLAY as the X server to which + // we will forward the proxied connections. + // This means that NX parameters have been + // passed through other means. + // + + display = getenv("DISPLAY"); + + if (display == NULL || *display == '\0') + { + #ifdef PANIC + *logofs << "Loop: PANIC! Host X server DISPLAY is not set.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Host X server DISPLAY is not set.\n"; + + HandleCleanup(); + } + else if (strncasecmp(display, "nx/nx,", 6) == 0 || + strncasecmp(display, "nx,", 3) == 0 || + strncasecmp(display, "nx/nx:", 6) == 0 || + strncasecmp(display, "nx:", 3) == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! NX transport on host X server '" + << display << "' not supported.\n" << logofs_flush; + #endif + + cerr << "Error" << ": NX transport on host X server '" + << display << "' not supported.\n"; + + cerr << "Error" << ": Please run the local proxy specifying " + << "the host X server to connect to.\n"; + + HandleCleanup(); + } + else if (strlen(display) >= DEFAULT_STRING_LENGTH) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Host X server DISPLAY cannot exceed " + << DEFAULT_STRING_LENGTH << " characters.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Host X server DISPLAY cannot exceed " + << DEFAULT_STRING_LENGTH << " characters.\n"; + + HandleCleanup(); + } + + strcpy(displayHost, display); + } + + display = new char[strlen(displayHost) + 1]; + + if (display == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Out of memory handling DISPLAY variable.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Out of memory handling DISPLAY variable.\n"; + + HandleCleanup(); + } + + strcpy(display, displayHost); + + #ifdef __APPLE__ + + if ((strncasecmp(display, "/tmp/launch", 11) == 0) || (strncasecmp(display, "/private/tmp/com.apple.launchd", 30) == 0)) + { + #ifdef TEST + *logofs << "Loop: Using launchd service on socket '" + << display << "'.\n" << logofs_flush; + #endif + + useLaunchdSocket = 1; + } + + #endif + + char *separator = strrchr(display, ':'); + + if ((separator == NULL) || !isdigit(*(separator + 1))) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid display '" << display << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Invalid display '" << display << "'.\n"; + + HandleCleanup(); + } + + *separator = '\0'; + + xPort = atoi(separator + 1); + + #ifdef TEST + *logofs << "Loop: Using local X display '" << displayHost + << "' with host '" << display << "' and port '" + << xPort << "'.\n" << logofs_flush; + #endif + + #ifdef __APPLE__ + + if (separator == display || strcmp(display, "unix") == 0 || + useLaunchdSocket == 1) + + #else + + if (separator == display || strcmp(display, "unix") == 0) + + #endif + { + // + // UNIX domain port. + // + + #ifdef TEST + *logofs << "Loop: Using real X server on UNIX domain socket.\n" + << logofs_flush; + #endif + + sockaddr_un *xServerAddrUNIX = new sockaddr_un; + + xServerAddrFamily = AF_UNIX; + xServerAddrUNIX -> sun_family = AF_UNIX; + + // + // The scope of this function is to fill either the sockaddr_un + // (when the display is set to the Unix Domain socket) or the + // sockaddr_in structure (when connecting by TCP) only once, so + // that the structure will be later used at the time the server + // proxy will try to forward the connection to the X server. We + // don't need to verify that the socket does exist at the pre- + // sent moment. The method that forwards the connection will + // perform the required checks and will retry, if needed. Anyway + // we need to select the name of the socket, so we check if the + // well-known directory exists and take that as an indication of + // where the socket will be created. + // + + // Try abstract X11 socket first (via a test connect), if that fails + // fall back to Unix domain socket file. + + #ifdef __linux__ + int testSocketFD; + testSocketFD = socket(xServerAddrFamily, SOCK_STREAM, PF_UNSPEC); + + int len = sprintf(unixSocketName + 1, "/tmp/.X11-unix/X%d", xPort); + unixSocketName[0] = '\0'; + + sockaddr_un *xServerAddrABSTRACT = new sockaddr_un; + memset(xServerAddrABSTRACT, 0, xServerAddrLength); + xServerAddrABSTRACT -> sun_family = AF_UNIX; + memcpy(xServerAddrABSTRACT -> sun_path, unixSocketName, len+1); + xServerAddrLength = len +3; + + int ret = connect(testSocketFD, (struct sockaddr *) xServerAddrABSTRACT, xServerAddrLength); + if (ret == 0) { + + cerr << "Info" << ": Using abstract X11 socket in kernel namespace " + << "for accessing DISPLAY=:" << xPort << ".\n"; + + close(testSocketFD); + xServerAddr = (sockaddr *) xServerAddrABSTRACT; + return 1; + + } else { + + cerr << "Info" << ": Falling back to file system X11 socket " + << "for accessing DISPLAY=:" << xPort << ".\n"; + + #endif + + struct stat statInfo; + + char unixSocketDir[DEFAULT_STRING_LENGTH]; + + snprintf(unixSocketDir, DEFAULT_STRING_LENGTH - 1, "%s/.X11-unix", + control -> TempPath); + + #ifdef __APPLE__ + + if (useLaunchdSocket == 1) + { + char *slash = rindex(display, '/'); + + if (slash != NULL) + { + *slash = '\0'; + } + + snprintf(unixSocketDir, DEFAULT_STRING_LENGTH - 1, "%s", display); + } + + #endif + + *(unixSocketDir + DEFAULT_STRING_LENGTH - 1) = '\0'; + + #ifdef TEST + *logofs << "Loop: Assuming X socket in directory '" + << unixSocketDir << "'.\n" << logofs_flush; + #endif + + if (stat(unixSocketDir, &statInfo) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't determine the location of " + << "the X display socket.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't determine the location of " + << "the X display socket.\n"; + + #ifdef PANIC + *logofs << "Loop: PANIC! Error " << EGET() << " '" << ESTR() + << "' checking '" << unixSocketDir << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error " << EGET() << " '" << ESTR() + << "' checking '" << unixSocketDir << "'.\n"; + + HandleCleanup(); + } + + sprintf(unixSocketName, "%s/X%d", unixSocketDir, xPort); + + #ifdef __APPLE__ + + if (useLaunchdSocket == 1) + { + strncpy(unixSocketName, displayHost, DEFAULT_STRING_LENGTH - 1); + } + + #endif + + #ifdef TEST + *logofs << "Loop: Assuming X socket name '" << unixSocketName + << "'.\n" << logofs_flush; + #endif + + strcpy(xServerAddrUNIX -> sun_path, unixSocketName); + + xServerAddr = (sockaddr *) xServerAddrUNIX; + xServerAddrLength = sizeof(sockaddr_un); + + #ifdef __linux__ + + } + #endif + } + else + { + // + // TCP port. + // + + #ifdef TEST + *logofs << "Loop: Using real X server on TCP port.\n" + << logofs_flush; + #endif + + xServerAddrFamily = AF_INET; + + int xServerIPAddr = GetHostAddress(display); + + if (xServerIPAddr == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Unknown display host '" << display + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unknown display host '" << display + << "'.\n"; + + HandleCleanup(); + } + + sockaddr_in *xServerAddrTCP = new sockaddr_in; + + xServerAddrTCP -> sin_family = AF_INET; + xServerAddrTCP -> sin_port = htons(X_TCP_PORT + xPort); + xServerAddrTCP -> sin_addr.s_addr = xServerIPAddr; + + xServerAddr = (sockaddr *) xServerAddrTCP; + xServerAddrLength = sizeof(sockaddr_in); + } + + delete [] display; + + return 1; +} + +int SetupServiceSockets() +{ + if (control -> ProxyMode == proxy_client) + { + if (useCupsSocket) + { + if ((cupsFD = ListenConnection(cupsPort, "CUPS")) < 0) + { + useCupsSocket = 0; + } + } + + if (useAuxSocket) + { + if ((auxFD = ListenConnection(auxPort, "auxiliary X11")) < 0) + { + useAuxSocket = 0; + } + } + + if (useSmbSocket) + { + if ((smbFD = ListenConnection(smbPort, "SMB")) < 0) + { + useSmbSocket = 0; + } + } + + if (useMediaSocket) + { + if ((mediaFD = ListenConnection(mediaPort, "media")) < 0) + { + useMediaSocket = 0; + } + } + + if (useHttpSocket) + { + if ((httpFD = ListenConnection(httpPort, "http")) < 0) + { + useHttpSocket = 0; + } + } + + useFontSocket = 0; + } + else + { + // + // Get ready to listen for the font server connections + // + + if (useFontSocket) + { + // Since ProtoStep7 (#issue 108) + int port = atoi(fontPort); + + if ((fontFD = ListenConnectionTCP("localhost", port, "font")) < 0) + { + useFontSocket = 0; + } + } + + useCupsSocket = 0; + useAuxSocket = 0; + useSmbSocket = 0; + useMediaSocket = 0; + useHttpSocket = 0; + } + + // + // Slave channels can be originated + // by both sides. + // + + if (useSlaveSocket) + { + // Since ProtoStep7 (#issue 108) + if ((slaveFD = ListenConnection(slavePort, "slave")) < 0) + { + useSlaveSocket = 0; + } + } + + return 1; +} + +int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label) +{ + int newFD = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC); + + if (newFD == -1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to socket failed for " << label + << " socket. Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to socket failed for " << label + << " socket. Error is " << EGET() << " '" + << ESTR() << "'.\n"; + + goto SetupSocketError; + } + + if (addr->sa_family == AF_INET) + if (SetReuseAddress(newFD) < 0) + { + // SetReuseAddress already warns with an error + goto SetupSocketError; + } + + if (bind(newFD, addr, addrlen) == -1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to bind failed for " << label + << ". Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to bind failed for " << label + << ". Error is " << EGET() + << " '" << ESTR() << "'.\n"; + goto SetupSocketError; + } + + if (listen(newFD, 8) == -1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to listen failed for " << label + << ". Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to listen failed for " << label + << ". Error is " << EGET() + << " '" << ESTR() << "'.\n"; + + goto SetupSocketError; + } + + return newFD; + +SetupSocketError: + + if (newFD != -1) + { + close(newFD); + } + + // + // May optionally return. The session would + // continue without the service. The problem + // with this approach is that it would make + // harder to track problems with allocation + // of ports in clients and server. + // + + HandleCleanup(); + return -1; +} + +int ListenConnectionUnix(const char *path, const char *label) +{ + + sockaddr_un unixAddr; + unixAddr.sun_family = AF_UNIX; +#ifdef UNIX_PATH_MAX + if (strlen(path) >= UNIX_PATH_MAX) +#else + if (strlen(path) >= sizeof(unixAddr.sun_path)) +#endif + { + #ifdef PANIC + *logofs << "Loop: PANIC! Socket path \"" << path << "\" for " + << label << " is too long.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Socket path \"" << path << "\" for " + << label << " is too long.\n"; + + HandleCleanup(); + return -1; + } + + strcpy(unixAddr.sun_path, path); + return ListenConnectionAny((sockaddr *)&unixAddr, sizeof(unixAddr), label); +} + +int ListenConnectionTCP(const char *host, long port, const char *label) +{ + sockaddr_in tcpAddr; + tcpAddr.sin_family = AF_INET; + tcpAddr.sin_port = htons(port); + + if (loopbackBind || + !host || + !strcmp(host, "") || + !strcmp(host, "localhost")) { + tcpAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + else if(strcmp(host, "*") == 0) { + tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY); + } + else { + int ip = tcpAddr.sin_addr.s_addr = GetHostAddress(host); + if (ip == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Unknown " << label << " host '" << host + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unknown " << label << " host '" << host + << "'.\n"; + + HandleCleanup(); + return -1; + } + } + + return ListenConnectionAny((sockaddr *)&tcpAddr, sizeof(tcpAddr), label); +} + +int ListenConnection(ChannelEndPoint &endpoint, const char *label) +{ + char *unixPath, *host; + long port; + if (endpoint.getUnixPath(&unixPath)) { + return ListenConnectionUnix(unixPath, label); + } + else if (endpoint.getTCPHostAndPort(&host, &port)) { + return ListenConnectionTCP(host, port, label); + } + return -1; +} + +static int AcceptConnection(int fd, int domain, const char *label) +{ + struct sockaddr newAddr; + + socklen_t addrLen = sizeof(newAddr); + + #ifdef TEST + + if (domain == AF_UNIX) + { + *logofs << "Loop: Going to accept new Unix " << label + << " connection on FD#" << fd << ".\n" + << logofs_flush; + } + else + { + *logofs << "Loop: Going to accept new TCP " << label + << " connection on FD#" << fd << ".\n" + << logofs_flush; + } + + #endif + + int newFD = accept(fd, &newAddr, &addrLen); + + if (newFD < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to accept failed for " + << label << " connection. Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to accept failed for " + << label << " connection. Error is " << EGET() + << " '" << ESTR() << "'.\n"; + } + + return newFD; +} + +void HandleShutdown() +{ + if (proxy -> getShutdown() == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! No shutdown of proxy link " + << "performed by remote proxy.\n" + << logofs_flush; + #endif + + // + // Close the socket before showing the alert. + // It seems that the closure of the socket can + // sometimes take several seconds, even after + // the connection is broken. The result is that + // the dialog can be shown long after the user + // has gone after the failed session. Note that + // disabling the linger timeout does not seem + // to make any difference. + // + + CleanupSockets(); + + cerr << "Error" << ": Connection with remote peer broken.\n"; + + #ifdef TEST + *logofs << "Loop: Bytes received so far are " + << (unsigned long long) statistics -> getBytesIn() + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Please check the state of your " + << "network and retry.\n"; + + handleTerminatingInLoop(); + + if (control -> ProxyMode == proxy_server) + { + #ifdef TEST + *logofs << "Loop: Showing the proxy abort dialog.\n" + << logofs_flush; + #endif + + HandleAlert(ABORT_PROXY_CONNECTION_ALERT, 1); + + handleAlertInLoop(); + } + } + #ifdef TEST + else + { + *logofs << "Loop: Finalized the remote proxy shutdown.\n" + << logofs_flush; + } + #endif + + HandleCleanup(); +} + + +void WaitCleanup() +{ + T_timestamp selectTs; + + while (NXTransRunning(NX_FD_ANY)) + { + setTimestamp(selectTs, control -> PingTimeout); + + NXTransContinue(&selectTs); + } +} + +int KillProcess(int pid, const char *label, int signal, int wait) +{ + if (pid > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Killing the " << label << " process '" + << pid << "' from process with pid '" << getpid() + << "' with signal '" << DumpSignal(signal) + << "'.\n" << logofs_flush; + #endif + + signal = (signal == 0 ? SIGTERM : signal); + + if (kill(pid, signal) < 0 && EGET() != ESRCH) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Couldn't kill the " << label + << " process with pid '" << pid << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Couldn't kill the " << label + << " process with pid '" << pid << "'.\n"; + } + + if (wait == 1) + { + WaitChild(pid, label, 1); + } + + return 1; + } + else + { + #ifdef TEST + *logofs << "Loop: No " << label << " process " + << "to kill with pid '" << pid + << "'.\n" << logofs_flush; + #endif + + return 0; + } +} + +int CheckProcess(int pid, const char *label) +{ + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Checking the " << label << " process '" + << pid << "' from process with pid '" << getpid() + << "'.\n" << logofs_flush; + #endif + + if (kill(pid, SIGCONT) < 0 && EGET() == ESRCH) + { + #ifdef WARNING + *logofs << "Loop: WARNING! The " << label << " process " + << "with pid '" << pid << "' has exited.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": The " << label << " process " + << "with pid '" << pid << "' has exited.\n"; + + return 0; + } + + return 1; +} + +int StartKeeper() +{ + #if defined(TEST) || defined(INFO) + + if (IsRunning(lastKeeper) == 1 || + IsRestarting(lastKeeper) == 1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! The house-keeping process is " + << "alreay running with pid '" << lastKeeper + << "'.\n" << logofs_flush; + #endif + + HandleCleanup(); + } + + #endif + + // + // Don't care harvesting the persistent caches if + // the memory cache is not enabled. If the memory + // cache is not enabled neither we produced per- + // sistent caches. The user can still delete any + // persistent cache produced by the previous runs + // by using the client GUI. + // + // TODO: At the moment the user doesn't have a way + // to specify the amount of disk space to use for + // the persistent caches, but only the amount of + // space to use for images. + // + + if (control -> LocalTotalStorageSize > 0) + { + #ifdef TEST + *logofs << "Loop: Starting the house-keeping process with " + << "storage size " << control -> PersistentCacheDiskLimit + << ".\n" << logofs_flush; + #endif + + lastKeeper = NXTransKeeper(control -> PersistentCacheDiskLimit, + 0, control -> RootPath); + + if (IsFailed(lastKeeper)) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Failed to start the NX keeper process.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Failed to start the NX keeper process.\n"; + + SetNotRunning(lastKeeper); + } + #ifdef TEST + else + { + *logofs << "Loop: Keeper started with pid '" + << lastKeeper << "'.\n" << logofs_flush; + } + #endif + } + #ifdef TEST + else + { + *logofs << "Loop: Nothing to do for the keeper process " + << "with persistent cache not enabled.\n" + << logofs_flush; + } + #endif + + return 1; +} + +void HandleCleanupForReconnect() +{ + #ifdef TEST + *logofs << "Loop: Going to clean up system resources for Reconnect " + << "in process '" << getpid() << "'.\n" + << logofs_flush; + #endif + handleTerminatedInLoop(); + DisableSignals(); + if (control) + CleanupChildren(); + CleanupListeners(); + CleanupSockets(); + CleanupKeeper(); + CleanupStreams(); + CleanupLocal(); + CleanupGlobal(); + RestoreSignals(); + ServerCache::lastInitReply.set(0,NULL); + ServerCache::lastKeymap.set(0,NULL); + ServerCache::getKeyboardMappingLastMap.set(0,NULL); +} +void HandleCleanup(int code) +{ + #ifdef TEST + *logofs << "Loop: Going to clean up system resources " + << "in process '" << getpid() << "'.\n" + << logofs_flush; + #endif + + handleTerminatedInLoop(); + + // + // Suspend any signal while cleaning up. + // + + DisableSignals(); + + if (getpid() == lastProxy) + { + // + // Terminate all the children. + // + + CleanupChildren(); + + // + // Close all listeners. + // + + CleanupListeners(); + + // + // Close all sockets. + // + + CleanupSockets(); + + // + // Release the global objects. + // + + CleanupGlobal(); + + // + // Restore the original signal handlers. + // + + RestoreSignals(); + } + + // + // This is our last chance to print a message. If this + // is the process which created the transport we will + // jump back into the loop, letting the caller find out + // that the connection is broken, otherwise we assume + // that this is a child of the proxy and so we will + // safely exit. + // + + #ifdef TEST + + if (getpid() == lastProxy) + { + *logofs << "Loop: Reverting to loop context in process with " + << "pid '" << getpid() << "' at " << strMsTimestamp() + << ".\n" << logofs_flush; + } + else + { + *logofs << "Loop: Exiting from child process with pid '" + << getpid() << "' at " << strMsTimestamp() + << ".\n" << logofs_flush; + } + + #endif + + if (getpid() == lastProxy) + { + // + // Reset all values to their default. + // + + CleanupLocal(); + + CleanupStreams(); + + longjmp(context, 1); + } + else + { + // + // Give a last chance to the process + // to cleanup the ancillary classes. + // + + CleanupKeeper(); + + CleanupStreams(); + + exit(code); + } +} + +void CleanupKeeper() +{ + if (keeper != NULL) + { + #ifdef TEST + *logofs << "Loop: Freeing up keeper in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + delete keeper; + + keeper = NULL; + } +} + +void CleanupStreams() +{ + // + // TODO: The cleanup procedure skips deletion of + // the I/O streams under Windows. This is intended + // to avoid a strange segfault occurring randomly, + // at the time the proxy is being shut down. + // + + #ifndef __CYGWIN32__ + + #ifdef TEST + *logofs << "Loop: Freeing up streams in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + if (logofs != NULL && logofs != &cerr && + *errorsFileName != '\0') + { + *logofs << flush; + + delete logofs; + + // + // Let the log go again to the standard + // error. + // + + logofs = &cerr; + } + + if (statofs != NULL && statofs != &cerr && + *statsFileName != '\0') + { + *statofs << flush; + + delete statofs; + + statofs = NULL; + } + + if (errofs != NULL) + { + *errofs << flush; + + if (errofs == &cerr) + { + errofs = NULL; + } + else if (errsbuf != NULL) + { + cerr.rdbuf(errsbuf); + + errsbuf = NULL; + + delete errofs; + } + + errofs = NULL; + } + + #endif /* #ifndef __CYGWIN32__ */ + + // + // Reset these as they can't be reset + // in CleanupLocal(). + // + + *sessionFileName = '\0'; + *errorsFileName = '\0'; + *optionsFileName = '\0'; + *statsFileName = '\0'; +} + +void CleanupChildren() +{ + // + // Remove any watchdog. + // + + if (IsRunning(lastWatchdog)) + { + KillProcess(lastWatchdog, "watchdog", SIGTERM, 1); + + SetNotRunning(lastWatchdog); + + lastSignal = 0; + } + + // + // Kill the cache house-keeping process. + // + + if (IsRunning(lastKeeper)) + { + KillProcess(lastKeeper, "house-keeping", SIGTERM, 1); + + SetNotRunning(lastKeeper); + } + + // + // Let any running dialog to continue until it is + // closed by the user. In general this is the exp- + // ected behaviour, as for example when we are + // exiting because the link was abrouptedly shut + // down. + // + + if (IsRunning(lastDialog)) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: WARNING! Leaving the dialog process '" + << lastDialog << "' running in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + SetNotRunning(lastDialog); + } + + // + // Give user a chance to start a new session. + // + + if (control -> EnableRestartOnShutdown == 1) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Respawning the NX client " + << "on display '" << displayHost << "'.\n" + << logofs_flush; + #endif + + NXTransClient(displayHost); + } + + for (int i = 0; i < control -> KillDaemonOnShutdownNumber; i++) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Killing the NX daemon with " + << "pid '" << control -> KillDaemonOnShutdown[i] + << "'.\n" << logofs_flush; + #endif + + KillProcess(control -> KillDaemonOnShutdown[i], "daemon", SIGTERM, 0); + } +} + +void CleanupGlobal() +{ + if (proxy != NULL) + { + #ifdef TEST + *logofs << "Loop: Freeing up proxy in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + delete proxy; + + proxy = NULL; + } + + if (agent != NULL) + { + #ifdef TEST + *logofs << "Loop: Freeing up agent in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + delete agent; + + agent = NULL; + } + + if (auth != NULL) + { + #ifdef TEST + *logofs << "Loop: Freeing up auth data in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + delete auth; + + auth = NULL; + } + + if (statistics != NULL) + { + #ifdef TEST + *logofs << "Loop: Freeing up statistics in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + delete statistics; + + statistics = NULL; + } + + if (control != NULL) + { + #ifdef TEST + *logofs << "Loop: Freeing up control in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + delete control; + + control = NULL; + } +} + +void CleanupConnections() +{ + if (proxy -> getChannels(channel_x11) != 0) + { + #ifdef TEST + *logofs << "Loop: Closing any remaining X connections.\n" + << logofs_flush; + #endif + + proxy -> handleCloseAllXConnections(); + + #ifdef TEST + *logofs << "Loop: Closing any remaining listener.\n" + << logofs_flush; + #endif + + proxy -> handleCloseAllListeners(); + } + + proxy -> handleFinish(); +} + +void CleanupListeners() +{ + if (useTcpSocket == 1) + { + if (tcpFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing TCP listener in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(tcpFD); + + tcpFD = -1; + } + + useTcpSocket = 0; + } + + if (useUnixSocket == 1) + { + if (unixFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing UNIX listener in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(unixFD); + + unixFD = -1; + } + + if (*unixSocketName != '\0') + { + #ifdef TEST + *logofs << "Loop: Going to remove the Unix domain socket '" + << unixSocketName << "' in process " << "with pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + unlink(unixSocketName); + } + + useUnixSocket = 0; + } + + if (useAgentSocket == 1) + { + // + // There is no listener for the + // agent descriptor. + // + + useAgentSocket = 0; + } + + if (useCupsSocket == 1) + { + if (cupsFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing CUPS listener in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(cupsFD); + + cupsFD = -1; + } + + useCupsSocket = 0; + } + + if (useAuxSocket == 1) + { + if (auxFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing auxiliary X11 listener " + << "in process " << "with pid '" << getpid() + << "'.\n" << logofs_flush; + #endif + + close(auxFD); + + auxFD = -1; + } + + useAuxSocket = 0; + } + + if (useSmbSocket == 1) + { + if (smbFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing SMB listener in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(smbFD); + + smbFD = -1; + } + + useSmbSocket = 0; + } + + if (useMediaSocket == 1) + { + if (mediaFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing multimedia listener in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(mediaFD); + + mediaFD = -1; + } + + useMediaSocket = 0; + } + + if (useHttpSocket == 1) + { + if (httpFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing http listener in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(httpFD); + + httpFD = -1; + } + + useHttpSocket = 0; + } + + if (useFontSocket == 1) + { + if (fontFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing font server listener in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(fontFD); + + fontFD = -1; + } + + useFontSocket = 0; + } + + if (useSlaveSocket == 1) + { + if (slaveFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing slave listener in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(slaveFD); + + slaveFD = -1; + } + + useSlaveSocket = 0; + } +} + +void CleanupSockets() +{ + if (proxyFD != -1) + { + #ifdef TEST + *logofs << "Loop: Closing proxy FD in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(proxyFD); + + proxyFD = -1; + } + + if (agentFD[1] != -1) + { + #ifdef TEST + *logofs << "Loop: Closing agent FD in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + close(agentFD[1]); + + agentFD[0] = -1; + agentFD[1] = -1; + } +} + +void CleanupLocal() +{ + *homeDir = '\0'; + *rootDir = '\0'; + *tempDir = '\0'; + *systemDir = '\0'; + *sessionDir = '\0'; + + *linkSpeedName = '\0'; + *cacheSizeName = '\0'; + *shsegSizeName = '\0'; + *imagesSizeName = '\0'; + *bitrateLimitName = '\0'; + *packMethodName = '\0'; + *productName = '\0'; + + packMethod = -1; + packQuality = -1; + + *sessionType = '\0'; + *sessionId = '\0'; + + parsedOptions = 0; + parsedCommand = 0; + + *remoteData = '\0'; + remotePosition = 0; + + tcpFD = -1; + unixFD = -1; + cupsFD = -1; + auxFD = -1; + smbFD = -1; + mediaFD = -1; + httpFD = -1; + fontFD = -1; + slaveFD = -1; + proxyFD = -1; + + agentFD[0] = -1; + agentFD[1] = -1; + + useUnixSocket = 1; + useTcpSocket = 1; + useCupsSocket = 0; + useAuxSocket = 0; + useSmbSocket = 0; + useMediaSocket = 0; + useHttpSocket = 0; + useFontSocket = 0; + useSlaveSocket = 0; + useAgentSocket = 0; + + useNoDelay = -1; + usePolicy = -1; + useRender = -1; + useTaint = -1; + + *unixSocketName = '\0'; + + *acceptHost = '\0'; + *displayHost = '\0'; + *authCookie = '\0'; + + proxyPort = DEFAULT_NX_PROXY_PORT; + xPort = DEFAULT_NX_X_PORT; + + xServerAddrFamily = -1; + xServerAddrLength = 0; + + delete xServerAddr; + + xServerAddr = NULL; + + listenSocket.disable(); + connectSocket.disable(); + + cupsPort.disable(); + auxPort.disable(); + smbPort.disable(); + mediaPort.disable(); + httpPort.disable(); + slavePort.disable(); + + *fontPort = '\0'; + + *bindHost = '\0'; + bindPort = -1; + + initTs = nullTimestamp(); + startTs = nullTimestamp(); + logsTs = nullTimestamp(); + nowTs = nullTimestamp(); + + diffTs = 0; + + lastProxy = 0; + lastDialog = 0; + lastWatchdog = 0; + lastKeeper = 0; + lastStatus = 0; + lastKill = 0; + lastDestroy = 0; + + lastReadableTs = nullTimestamp(); + + lastAlert.code = 0; + lastAlert.local = 0; + + lastMasks.blocked = 0; + lastMasks.installed = 0; + + memset(&lastMasks.saved, 0, sizeof(sigset_t)); + + for (int i = 0; i < 32; i++) + { + lastMasks.enabled[i] = 0; + lastMasks.forward[i] = 0; + + memset(&lastMasks.action[i], 0, sizeof(struct sigaction)); + } + + lastSignal = 0; + + memset(&lastTimer.action, 0, sizeof(struct sigaction)); + memset(&lastTimer.value, 0, sizeof(struct itimerval)); + + lastTimer.start = nullTimestamp(); + lastTimer.next = nullTimestamp(); +} + +int CheckAbort() +{ + if (lastSignal != 0) + { + #ifdef TEST + *logofs << "Loop: Aborting the procedure due to signal '" + << lastSignal << "', '" << DumpSignal(lastSignal) + << "'.\n" << logofs_flush; + #endif + + cerr << "Info" << ": Aborting the procedure due to signal '" + << lastSignal << "'.\n"; + + lastSignal = 0; + + return 1; + } + + return 0; +} + +void HandleAbort() +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + *logofs << flush; + + handleTerminatingInLoop(); + + if (lastSignal == SIGHUP) + { + lastSignal = 0; + } + + // + // The current default is to just quit the program. + // Code has not been updated to deal with the new + // NX transport loop. + // + + if (control -> EnableCoreDumpOnAbort == 1) + { + if (agent != NULL) + { + cerr << "Session" << ": Terminating session at '" + << strTimestamp() << "'.\n"; + } + + cerr << "Error" << ": Generating a core file to help " + << "the investigations.\n"; + + cerr << "Session" << ": Session terminated at '" + << strTimestamp() << "'.\n"; + + cerr << flush; + + signal(SIGABRT, SIG_DFL); + + raise(SIGABRT); + } + + #ifdef TEST + *logofs << "Loop: Showing the proxy abort dialog.\n" + << logofs_flush; + #endif + + if (control -> ProxyMode == proxy_server) + { + // + // Close the socket before showing the alert. + // It seems that the closure of the socket can + // sometimes take several seconds, even after + // the connection is broken. + // + + CleanupSockets(); + + if (lastKill == 0) + { + HandleAlert(ABORT_PROXY_CONNECTION_ALERT, 1); + } + else + { + HandleAlert(ABORT_PROXY_SHUTDOWN_ALERT, 1); + } + + handleAlertInLoop(); + } + + HandleCleanup(); +} + +void HandleAlert(int code, int local) +{ + if (lastAlert.code == 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Requesting an alert dialog with code " + << code << " and local " << local << ".\n" + << logofs_flush; + #endif + + lastAlert.code = code; + lastAlert.local = local; + } + #if defined(TEST) || defined(INFO) + else + { + *logofs << "Loop: WARNING! Alert dialog already requested " + << "with code " << lastAlert.code << ".\n" + << logofs_flush; + } + #endif + + return; +} + +void FlushCallback(int length) +{ + if (flushCallback != NULL) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Reporting a flush request at " + << strMsTimestamp() << " with " << length + << " bytes written.\n" << logofs_flush; + #endif + + (*flushCallback)(flushParameter, length); + } + #if defined(TEST) || defined(INFO) + else if (control -> ProxyMode == proxy_client) + { + *logofs << "Loop: WARNING! Can't find a flush " + << "callback in process with pid '" << getpid() + << "'.\n" << logofs_flush; + } + #endif +} + +void KeeperCallback() +{ + if (IsRunning(lastKeeper) == 0) + { + // + // Let the house-keeping process take care + // of the persistent image cache. + // + + if (control -> ImageCacheEnableLoad == 1 || + control -> ImageCacheEnableSave == 1) + { + #ifdef TEST + *logofs << "Loop: Starting the house-keeping process with " + << "image storage size " << control -> ImageCacheDiskLimit + << ".\n" << logofs_flush; + #endif + + lastKeeper = NXTransKeeper(0, control -> ImageCacheDiskLimit, + control -> RootPath); + + if (IsFailed(lastKeeper)) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Can't start the NX keeper process.\n" + << logofs_flush; + #endif + + SetNotRunning(lastKeeper); + } + #ifdef TEST + else + { + *logofs << "Loop: Keeper started with pid '" + << lastKeeper << "'.\n" << logofs_flush; + } + #endif + } + #ifdef TEST + else + { + *logofs << "Loop: Nothing to do for the keeper process " + << "with image cache not enabled.\n" + << logofs_flush; + } + #endif + } + #ifdef TEST + else + { + *logofs << "Loop: Nothing to do with the keeper process " + << "already running.\n" << logofs_flush; + } + #endif +} + +void InstallSignals() +{ + #ifdef TEST + *logofs << "Loop: Installing signals in process with pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + for (int i = 0; i < 32; i++) + { + if (CheckSignal(i) == 1 && + lastMasks.enabled[i] == 0) + { + InstallSignal(i, NX_SIGNAL_ENABLE); + } + } + + lastMasks.installed = 1; +} + +void RestoreSignals() +{ + #ifdef TEST + *logofs << "Loop: Restoring signals in process with pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + if (lastMasks.installed == 1) + { + // + // Need to keep monitoring the children. + // + + for (int i = 0; i < 32; i++) + { + if (lastMasks.enabled[i] == 1) + { + RestoreSignal(i); + } + } + } + + lastMasks.installed = 0; + + if (lastMasks.blocked == 1) + { + EnableSignals(); + } +} + +void DisableSignals() +{ + if (lastMasks.blocked == 0) + { + sigset_t newMask; + + sigemptyset(&newMask); + + // + // Block also the other signals that may be + // installed by the agent, that are those + // signals for which the function returns 2. + // + + for (int i = 0; i < 32; i++) + { + if (CheckSignal(i) > 0) + { + #ifdef DUMP + *logofs << "Loop: Disabling signal " << i << " '" + << DumpSignal(i) << "' in process with pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + sigaddset(&newMask, i); + } + } + + sigprocmask(SIG_BLOCK, &newMask, &lastMasks.saved); + + lastMasks.blocked++; + } + #ifdef TEST + else + { + *logofs << "Loop: WARNING! Signals were already blocked in " + << "process with pid '" << getpid() << "'.\n" + << logofs_flush; + } + #endif +} + +void EnableSignals() +{ + if (lastMasks.blocked == 1) + { + #ifdef TEST + *logofs << "Loop: Enabling signals in process with pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + sigprocmask(SIG_SETMASK, &lastMasks.saved, NULL); + + lastMasks.blocked = 0; + } + else + { + #ifdef WARNING + *logofs << "Loop: WARNING! Signals were not blocked in " + << "process with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Signals were not blocked in " + << "process with pid '" << getpid() << "'.\n"; + } +} + +void InstallSignal(int signal, int action) +{ + if (lastMasks.enabled[signal] == 1) + { + if (action == NX_SIGNAL_FORWARD) + { + #ifdef TEST + *logofs << "Loop: Forwarding handler for signal " << signal + << " '" << DumpSignal(signal) << "' in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + lastMasks.forward[signal] = 1; + + return; + } + #ifdef TEST + else + { + *logofs << "Loop: Reinstalling handler for signal " << signal + << " '" << DumpSignal(signal) << "' in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + } + #endif + } + #ifdef TEST + else + { + *logofs << "Loop: Installing handler for signal " << signal + << " '" << DumpSignal(signal) << "' in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + } + #endif + + if (signal == SIGALRM && isTimestamp(lastTimer.start)) + { + ResetTimer(); + } + + struct sigaction newAction; + + memset(&newAction, 0, sizeof(newAction)); + + newAction.sa_handler = HandleSignal; + + sigemptyset(&(newAction.sa_mask)); + + if (signal == SIGCHLD) + { + newAction.sa_flags = SA_NOCLDSTOP; + } + else + { + newAction.sa_flags = 0; + } + + sigaction(signal, &newAction, &lastMasks.action[signal]); + + lastMasks.enabled[signal] = 1; + + if (action == NX_SIGNAL_FORWARD) + { + lastMasks.forward[signal] = 1; + } +} + +void RestoreSignal(int signal) +{ + if (lastMasks.enabled[signal] == 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Signal '" << DumpSignal(signal) + << " not installed in process with pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Signal '" << DumpSignal(signal) + << " not installed in process with pid '" + << getpid() << "'.\n"; + + return; + } + + #ifdef TEST + *logofs << "Loop: Restoring handler for signal " << signal + << " '" << DumpSignal(signal) << "' in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + if (signal == SIGALRM && isTimestamp(lastTimer.start)) + { + ResetTimer(); + } + + sigaction(signal, &lastMasks.action[signal], NULL); + + lastMasks.enabled[signal] = 0; + lastMasks.forward[signal] = 0; +} + +void HandleSignal(int signal) +{ + if (logofs == NULL) + { + logofs = &cerr; + } + + #if defined(UNSAFE) && (defined(TEST) || defined(INFO)) + + if (lastSignal != 0) + { + *logofs << "Loop: WARNING! Last signal is '" << lastSignal + << "', '" << DumpSignal(signal) << "' and not zero " + << "in process with pid '" << getpid() << "'.\n" + << logofs_flush; + } + + *logofs << "Loop: Signal '" << signal << "', '" + << DumpSignal(signal) << "' received in process " + << "with pid '" << getpid() << "'.\n" << logofs_flush; + + #endif + + if (getpid() != lastProxy && handler != NULL) + { + #if defined(UNSAFE) && (defined(TEST) || defined(INFO)) + *logofs << "Loop: Calling slave handler in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + if ((*handler)(signal) == 0) + { + return; + } + } + + switch (signal) + { + case SIGUSR1: + { + if (proxy != NULL && lastSignal == 0) + { + lastSignal = SIGUSR1; + } + + break; + } + case SIGUSR2: + { + if (proxy != NULL && lastSignal == 0) + { + lastSignal = SIGUSR2; + } + + break; + } + case SIGPIPE: + { + // + // It can happen that SIGPIPE is delivered + // to the proxy even in the case some other + // descriptor is unexpectedly closed. + // + // if (agentFD[1] != -1) + // { + // cerr << "Info" << ": Received signal 'SIGPIPE'. " + // << "Closing agent conection.\n"; + // + // shutdown(agentFD[1], SHUT_RDWR); + // } + // + + break; + } + case SIGALRM: + { + // + // Nothing to do. Just wake up the + // process on blocking operations. + // + + break; + } + case SIGCHLD: + { + // + // Check if any of our children has exited. + // + + if (HandleChildren() != 0) + { + signal = 0; + } + + // + // Don't save this signal or it will override + // any previous signal sent by child before + // exiting. + // + + break; + } + + #ifdef __CYGWIN32__ + + case 12: + { + // + // Nothing to do. This signal is what is delivered + // by the Cygwin library when trying use a shared + // memory function if the daemon is not running. + // + + #ifdef TEST + *logofs << "Loop: WARNING! Received signal '12' in " + << "process with pid '" << getpid() << "'.\n" + << logofs_flush; + + *logofs << "Loop: WARNING! Please check that the " + << "cygserver daemon is running.\n" + << logofs_flush; + #endif + + break; + } + + #endif + + default: + { + // + // Register the signal so we can handle it + // inside the main loop. We will probably + // dispose any resource and exit. + // + + if (getpid() == lastProxy) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Registering end of session request " + << "due to signal '" << signal << "', '" + << DumpSignal(signal) << "'.\n" + << logofs_flush; + #endif + + lastSignal = signal; + } + else + { + // + // This is a child, so exit immediately. + // + + HandleCleanup(); + } + } + } + + if (signal != 0 && lastMasks.forward[signal] == 1) + { + if (lastMasks.action[signal].sa_handler != NULL && + lastMasks.action[signal].sa_handler != HandleSignal) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Forwarding signal '" << signal << "', '" + << DumpSignal(signal) << "' to previous handler.\n" + << logofs_flush; + #endif + + lastMasks.action[signal].sa_handler(signal); + } + #ifdef WARNING + else if (lastMasks.action[signal].sa_handler == NULL) + { + *logofs << "Loop: WARNING! Parent requested to forward " + << "signal '" << signal << "', '" << DumpSignal(signal) + << "' but didn't set a handler.\n" << logofs_flush; + } + #endif + } +} + +int HandleChildren() +{ + // + // Try to waitpid() for each child because the + // call might have return ECHILD and so we may + // have lost any of the processes. + // + + if (IsRunning(lastDialog) && HandleChild(lastDialog) == 1) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Resetting pid of last dialog process " + << "in handler.\n" << logofs_flush; + #endif + + SetNotRunning(lastDialog); + + if (proxy != NULL) + { + proxy -> handleResetAlert(); + } + + return 1; + } + + if (IsRunning(lastWatchdog) && HandleChild(lastWatchdog) == 1) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Watchdog is gone. Setting the last " + << "signal to SIGHUP.\n" << logofs_flush; + #endif + + lastSignal = SIGHUP; + + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Resetting pid of last watchdog process " + << "in handler.\n" << logofs_flush; + #endif + + SetNotRunning(lastWatchdog); + + return 1; + } + + // + // The house-keeping process exits after a + // number of iterations to keep the memory + // pollution low. It is restarted on demand + // by the lower layers, using the callback + // function. + // + + if (IsRunning(lastKeeper) && HandleChild(lastKeeper) == 1) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Resetting pid of last house-keeping " + << "process in handler.\n" << logofs_flush; + #endif + + SetNotRunning(lastKeeper); + + return 1; + } + + // + // The pid will be checked by the code + // that registered the child. + // + + if (IsRunning(lastChild)) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Resetting pid of last child process " + << "in handler.\n" << logofs_flush; + #endif + + SetNotRunning(lastChild); + + return 1; + } + + proxy->checkSlaves(); + + // + // This can actually happen either because we + // reset the pid of the child process as soon + // as we kill it, or because of a child process + // of our parent. + // + + #if defined(UNSAFE) && (defined(TEST) || defined(INFO)) + *logofs << "Loop: Ignoring signal received for the " + << "unregistered child.\n" << logofs_flush; + #endif + + return 0; +} + +int HandleChild(int child) +{ + int pid; + + int status = 0; + int options = WNOHANG | WUNTRACED; + + while ((pid = waitpid(child, &status, options)) && + pid == -1 && EGET() == EINTR); + + return CheckChild(pid, status); +} + +int WaitChild(int child, const char* label, int force) +{ + int pid; + + int status = 0; + int options = WUNTRACED; + + for (;;) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Waiting for the " << label + << " process '" << child << "' to die.\n" + << logofs_flush; + #endif + + pid = waitpid(child, &status, options); + + if (pid == -1 && EGET() == EINTR) + { + if (force == 0) + { + return 0; + } + + #ifdef WARNING + *logofs << "Loop: WARNING! Ignoring signal while " + << "waiting for the " << label << " process '" + << child << "' to die.\n" + << logofs_flush; + #endif + + continue; + } + + break; + } + + return (EGET() == ECHILD ? 1 : CheckChild(pid, status)); +} + +int CheckChild(int pid, int status) +{ + lastStatus = 0; + + if (pid > 0) + { + if (WIFSTOPPED(status)) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Child process '" << pid << "' was stopped " + << "with signal " << (WSTOPSIG(status)) << ".\n" + << logofs_flush; + #endif + + return 0; + } + else + { + if (WIFEXITED(status)) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Child process '" << pid << "' exited " + << "with status '" << (WEXITSTATUS(status)) + << "'.\n" << logofs_flush; + #endif + + lastStatus = WEXITSTATUS(status); + } + else if (WIFSIGNALED(status)) + { + if (CheckSignal(WTERMSIG(status)) != 1) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Child process '" << pid + << "' died because of signal " << (WTERMSIG(status)) + << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Child process '" << pid + << "' died because of signal " << (WTERMSIG(status)) + << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n"; + } + #if defined(UNSAFE) && defined(TEST) + else + { + *logofs << "Loop: Child process '" << pid + << "' died because of signal " << (WTERMSIG(status)) + << ", '" << DumpSignal(WTERMSIG(status)) << "'.\n" + << logofs_flush; + } + #endif + + lastStatus = 1; + } + + return 1; + } + } + else if (pid < 0) + { + if (EGET() != ECHILD) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to waitpid failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to waitpid failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + HandleCleanup(); + } + + // + // This can happen when the waitpid() is + // blocking, as the SIGCHLD is received + // within the call. + // + + #ifdef TEST + *logofs << "Loop: No more children processes running.\n" + << logofs_flush; + #endif + + return 1; + } + + return 0; +} + +void RegisterChild(int child) +{ + #if defined(TEST) || defined(INFO) + + if (IsNotRunning(lastChild)) + { + *logofs << "Loop: Registering child process '" << child + << "' in process with pid '" << getpid() + << "'.\n" << logofs_flush; + } + else + { + *logofs << "Loop: WARNING! Overriding registered child '" + << lastChild << "' with new child '" << child + << "' in process with pid '" << getpid() + << "'.\n" << logofs_flush; + } + + #endif + + lastChild = child; +} + +int CheckParent(const char *name, const char *type, int parent) +{ + if (parent != getppid() || parent == 1) + { + #ifdef WARNING + *logofs << name << ": WARNING! Parent process appears " + << "to be dead. Exiting " << type << ".\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Parent process appears " + << "to be dead. Exiting " << type << ".\n"; + + return 0; + } + + return 1; +} + +void HandleTimer(int signal) +{ + if (signal == SIGALRM) + { + if (isTimestamp(lastTimer.start)) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Timer expired at " << strMsTimestamp() + << " in process with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + if (proxy != NULL) + { + proxy -> handleTimer(); + } + + ResetTimer(); + } + else + { + #ifdef PANIC + *logofs << "Loop: PANIC! Inconsistent timer state " + << " in process with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Inconsistent timer state " + << " in process with pid '" << getpid() << "'.\n"; + } + } + else + { + #ifdef PANIC + *logofs << "Loop: PANIC! Inconsistent signal '" + << signal << "', '" << DumpSignal(signal) + << "' received in process with pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Inconsistent signal '" + << signal << "', '" << DumpSignal(signal) + << "' received in process with pid '" + << getpid() << "'.\n"; + } +} + +void SetTimer(int value) +{ + getNewTimestamp(); + + if (isTimestamp(lastTimer.start)) + { + int diffTs = diffTimestamp(lastTimer.start, getTimestamp()); + + if (diffTs > lastTimer.next.tv_usec / 1000 * 2) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Timer missed to expire at " + << strMsTimestamp() << " in process with pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Timer missed to expire at " + << strMsTimestamp() << " in process with pid '" + << getpid() << "'.\n"; + + HandleTimer(SIGALRM); + } + else + { + #ifdef TEST + *logofs << "Loop: Timer already running at " + << strMsTimestamp() << " in process with pid '" + << getpid() << "'.\n" << logofs_flush; + #endif + + return; + } + } + + // + // Save the former handler. + // + + struct sigaction action; + + memset(&action, 0, sizeof(action)); + + action.sa_handler = HandleTimer; + + sigemptyset(&action.sa_mask); + + action.sa_flags = 0; + + sigaction(SIGALRM, &action, &lastTimer.action); + + // + // Start the timer. + // + + lastTimer.next = getTimestamp(value); + + struct itimerval timer; + + timer.it_interval = lastTimer.next; + timer.it_value = lastTimer.next; + + #ifdef TEST + *logofs << "Loop: Timer set to " << lastTimer.next.tv_sec + << " S and " << lastTimer.next.tv_usec / 1000 + << " Ms at " << strMsTimestamp() << " in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + if (setitimer(ITIMER_REAL, &timer, &lastTimer.value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to setitimer failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to setitimer failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + lastTimer.next = nullTimestamp(); + + return; + } + + lastTimer.start = getTimestamp(); +} + +void ResetTimer() +{ + if (isTimestamp(lastTimer.start) == 0) + { + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Timer not running in process " + << "with pid '" << getpid() << "'.\n" + << logofs_flush; + #endif + + return; + } + + #if defined(UNSAFE) && defined(TEST) + *logofs << "Loop: Timer reset at " << strMsTimestamp() + << " in process with pid '" << getpid() + << "'.\n" << logofs_flush; + #endif + + // + // Restore the old signal mask and timer. + // + + if (setitimer(ITIMER_REAL, &lastTimer.value, NULL) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to setitimer failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to setitimer failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + } + + if (sigaction(SIGALRM, &lastTimer.action, NULL) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to sigaction failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to sigaction failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + } + + lastTimer.start = lastTimer.next = nullTimestamp(); +} + +// +// Open TCP or UNIX file socket to listen for remote proxy +// and block until remote connects. If successful close +// the listening socket and return FD on which the other +// party is connected. +// + +int WaitForRemote(ChannelEndPoint &socketAddress) +{ + char hostLabel[DEFAULT_STRING_LENGTH] = { 0 }; + char *socketUri = NULL; + + int retryAccept = -1; + + int proxyFD = -1; + int newFD = -1; + + int acceptIPAddr = 0; + + if (socketAddress.isTCPSocket()) + { + + // + // Get IP address of host to be awaited. + // + + if (*acceptHost != '\0') + { + acceptIPAddr = GetHostAddress(acceptHost); + + if (acceptIPAddr == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Cannot accept connections from unknown host '" + << acceptHost << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot accept connections from unknown host '" + << acceptHost << "'.\n"; + + goto WaitForRemoteError; + } + snprintf(hostLabel, sizeof(hostLabel), "'%s'", acceptHost); + } + else + { + strcpy(hostLabel, "any host"); + } + + long bindPort; + if (socketAddress.getTCPHostAndPort(NULL, &bindPort)) + { + socketAddress.setSpec(loopbackBind ? "localhost" : "*", bindPort); + } + else + { + // This should never happen + cerr << "Error" << ": Unable to change bind host\n"; + } + } + else if (socketAddress.isUnixSocket()) + strcpy(hostLabel, "this host"); + else + strcpy(hostLabel, "unknown origin (something went wrong!!!)"); + + + proxyFD = ListenConnection(socketAddress, "NX"); + + socketAddress.getSpec(&socketUri); + #ifdef TEST + *logofs << "Loop: Waiting for connection from " + << hostLabel << " on socket '" << socketUri + << "'.\n" << logofs_flush; + #endif + cerr << "Info" << ": Waiting for connection from " + << hostLabel << " on socket '" << socketUri + << "'.\n"; + free(socketUri); + + // + // How many times to loop waiting for connections + // from the selected host? Each loop wait for at + // most 20 seconds so a default value of 3 gives + // a timeout of 1 minute. + // + // TODO: Handling of timeouts and retry attempts + // must be rewritten. + // + + retryAccept = control -> OptionProxyRetryAccept; + + for (;;) + { + fd_set readSet; + + FD_ZERO(&readSet); + FD_SET(proxyFD, &readSet); + + T_timestamp selectTs; + + selectTs.tv_sec = 20; + selectTs.tv_usec = 0; + + int result = select(proxyFD + 1, &readSet, NULL, NULL, &selectTs); + + getNewTimestamp(); + + if (result == -1) + { + if (EGET() == EINTR) + { + if (CheckAbort() != 0) + { + goto WaitForRemoteError; + } + + continue; + } + + #ifdef PANIC + *logofs << "Loop: PANIC! Call to select failed. Error is " + << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Call to select failed. Error is " + << EGET() << " '" << ESTR() << "'.\n"; + + goto WaitForRemoteError; + } + else if (result > 0 && FD_ISSET(proxyFD, &readSet)) + { + + sockaddr_in newAddrINET; + + if (socketAddress.isUnixSocket()) + { + socklen_t addrLen = sizeof(sockaddr_un); + newFD = accept(proxyFD, NULL, &addrLen); + } + else if (socketAddress.isTCPSocket()) + { + socklen_t addrLen = sizeof(sockaddr_in); + newFD = accept(proxyFD, (sockaddr *) &newAddrINET, &addrLen); + } + if (newFD == -1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to accept failed. Error is " + << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Call to accept failed. Error is " + << EGET() << " '" << ESTR() << "'.\n"; + + goto WaitForRemoteError; + } + + if (socketAddress.isUnixSocket()) + { + + char * unixPath = NULL; + socketAddress.getUnixPath(&unixPath); + #ifdef TEST + *logofs << "Loop: Accepted connection from this host on Unix file socket '" + << unixPath << "'.\n" + << logofs_flush; + #endif + + cerr << "Info" << ": Accepted connection from this host on Unix file socket '" + << unixPath << "'.\n"; + free(unixPath); + + break; + } + else if (socketAddress.isTCPSocket()) + { + + char *connectedHost = inet_ntoa(newAddrINET.sin_addr); + + if (*acceptHost == '\0' || (int) newAddrINET.sin_addr.s_addr == acceptIPAddr) + { + + #ifdef TEST + + unsigned int connectedPort = ntohs(newAddrINET.sin_port); + + *logofs << "Loop: Accepted connection from '" << connectedHost + << "' with port '" << connectedPort << "'.\n" + << logofs_flush; + #endif + + cerr << "Info" << ": Accepted connection from '" + << connectedHost << "'.\n"; + + break; + } + else + { + #ifdef PANIC + *logofs << "Loop: WARNING! Refusing connection from '" << connectedHost + << "' on port '" << socketAddress.getTCPPort() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Refusing connection from '" + << connectedHost << "'.\n"; + } + + // + // Not the best way to elude a DOS attack... + // + + sleep(5); + + close(newFD); + + } + + } + + if (--retryAccept == 0) + { + if (socketAddress.isUnixSocket()) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Connection via Unix file socket from this host " + << "could not be established.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Connection via Unix file socket from this host " + << "could not be established.\n"; + } + else if (*acceptHost == '\0') + { + #ifdef PANIC + *logofs << "Loop: PANIC! Connection with remote host " + << "could not be established.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Connection with remote host " + << "could not be established.\n"; + } + else + { + #ifdef PANIC + *logofs << "Loop: PANIC! Connection with remote host '" + << acceptHost << "' could not be established.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Connection with remote host '" + << acceptHost << "' could not be established.\n"; + } + + goto WaitForRemoteError; + } + else + { + handleCheckSessionInConnect(); + } + } + + close(proxyFD); + + return newFD; + +WaitForRemoteError: + + close(proxyFD); + + HandleCleanup(); +} + +int PrepareProxyConnectionTCP(char** hostName, long int* portNum, int* timeout, int* proxyFD, int* reason) +{ + + if (!proxyFD) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionTCP). " + << "'proxyFD' must not be a NULL pointer.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Implementation error (PrepareProxyConnectionTCP). " + << "'proxyFD' must not be a NULL pointer.\n"; + + return -1; + } + + if (!reason) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionTCP). " + << "'reason' must not be a NULL pointer.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Implementation error (PrepareProxyConnectionTCP). " + << "'reason' must not be a NULL pointer.\n"; + + return -1; + } + + int remoteIPAddr = GetHostAddress(*hostName); + if (remoteIPAddr == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Unknown remote host '" + << *hostName << "'.\n" << logofs_flush; + #endif + cerr << "Error" << ": Unknown remote host '" + << *hostName << "'.\n"; + + HandleCleanup(); + } + + #ifdef TEST + *logofs << "Loop: Connecting to remote host '" + << *hostName << ":" << *portNum << "'.\n" + << logofs_flush; + #endif + + cerr << "Info" << ": Connecting to remote host '" + << *hostName << ":" << *portNum << "'.\n" + << logofs_flush; + + *proxyFD = -1; + *reason = -1; + + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(*portNum); + addr.sin_addr.s_addr = remoteIPAddr; + + *proxyFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC); + *reason = EGET(); + + if (*proxyFD == -1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to socket failed. " + << "Error is " << *reason << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to socket failed. " + << "Error is " << *reason << " '" << ESTR() + << "'.\n"; + return -1; + + } + else if (SetReuseAddress(*proxyFD) < 0) + { + return -1; + } + + // + // Ensure operation is timed out + // if there is a network problem. + // + + if (timeout) + SetTimer(*timeout); + else + SetTimer(20000); + + int result = connect(*proxyFD, (sockaddr *) &addr, sizeof(sockaddr_in)); + + *reason = EGET(); + + ResetTimer(); + + return result; + +} + +int PrepareProxyConnectionUnix(char** path, int* timeout, int* proxyFD, int* reason) +{ + + if (!proxyFD) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionUnix). " + << "proxyFD must not be a NULL pointer.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Implementation error (PrepareProxyConnectionUnix). " + << "proxyFD must not be a NULL pointer.\n"; + + return -1; + } + + if (!reason) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Implementation error (PrepareProxyConnectionUnix). " + << "'reason' must not be a NULL pointer.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Implementation error (PrepareProxyConnectionUnix). " + << "'reason' must not be a NULL pointer.\n"; + + return -1; + } + + /* FIXME: Add socket file existence and permission checks */ + + *proxyFD = -1; + *reason = -1; + + sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, *path, 108 - 1); + + *proxyFD = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC); + *reason = EGET(); + + if (*proxyFD == -1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Call to socket failed. " + << "Error is " << *reason << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to socket failed. " + << "Error is " << *reason << " '" << ESTR() + << "'.\n"; + + return -1; + } + + // + // Ensure operation is timed out + // if there is a network problem. + // + + if (timeout) + SetTimer(*timeout); + else + SetTimer(20000); + + int result = connect(*proxyFD, (sockaddr *) &addr, sizeof(sockaddr_un)); + + *reason = EGET(); + + ResetTimer(); + + return result; +} + +// +// Connect to remote proxy. If successful +// return FD of connection, else return -1. +// + +int ConnectToRemote(ChannelEndPoint &socketAddress) +{ + + // + // How many times we retry to connect to remote + // host / Unix domain socket in case of failure? + // + + int retryConnect = control -> OptionProxyRetryConnect; + + // + // Show an alert after 20 seconds and use the + // same timeout to interrupt the connect. The + // retry timeout is incremental, starting from + // 100 miliseconds up to 1 second. + // + + int alertTimeout = 20000; + int connectTimeout = 20000; + int retryTimeout = 100; + + T_timestamp lastRetry = getNewTimestamp(); + + int result = -1; + int reason = -1; + int proxyFD = -1; + + char *hostName = NULL; + long int portNum = -1; + char *unixPath = NULL; + + for (;;) + { + + #ifdef DEBUG + *logofs << "Loop: Timer set to " << connectTimeout / 1000 + << " S " << "with retry set to " << retryConnect + << " in process with pid '" << getpid() + << "'.\n" << logofs_flush; + #endif + + if (socketAddress.getUnixPath(&unixPath)) + result = PrepareProxyConnectionUnix(&unixPath, &connectTimeout, &proxyFD, &reason); + else if (socketAddress.getTCPHostAndPort(&hostName, &portNum)) + result = PrepareProxyConnectionTCP(&hostName, &portNum, &connectTimeout, &proxyFD, &reason); + + if (result < 0) + { + close(proxyFD); + + if (CheckAbort() != 0) + { + goto ConnectToRemoteError; + } + else if (--retryConnect == 0) + { + ESET(reason); + + if (socketAddress.isUnixSocket()) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Connection to Unix file socket '" + << unixPath << "' failed. Error is " + << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Connection to Unix file socket '" + << unixPath << "' failed. Error is " + << EGET() << " '" << ESTR() << "'.\n"; + } + else + { + + #ifdef PANIC + *logofs << "Loop: PANIC! Connection to '" << hostName + << ":" << portNum << "' failed. Error is " + << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Connection to '" << hostName + << ":" << portNum << "' failed. Error is " + << EGET() << " '" << ESTR() << "'.\n"; + } + goto ConnectToRemoteError; + } + else + { + #ifdef TEST + *logofs << "Loop: Sleeping " << retryTimeout + << " ms before retrying.\n" + << logofs_flush; + #endif + + usleep(retryTimeout * 1000); + + retryTimeout <<= 1; + + if (retryTimeout > 1000 * 1000) + { + retryTimeout = 1000 * 1000; + } + } + + // + // Check if it is time to show an alert dialog. + // + + if (diffTimestamp(lastRetry, getNewTimestamp()) >= + (alertTimeout - control -> LatencyTimeout)) + { + if (IsNotRunning(lastDialog)) + { + handleCheckSessionInConnect(); + + // + // Wait for the dialog process to die + // unless a signal is received. + // + + while (IsRunning(lastDialog)) + { + WaitChild(lastDialog, "dialog", 0); + + if (CheckAbort() != 0) + { + // + // The client ignores the TERM signal + // on Windows. + // + + #ifdef __CYGWIN32__ + + KillProcess(lastDialog, "dialog", SIGKILL, 1); + + #else + + KillProcess(lastDialog, "dialog", SIGTERM, 1); + + #endif + + goto ConnectToRemoteError; + } + } + + lastRetry = getTimestamp(); + } + } + #ifdef TEST + { + *logofs << "Loop: Not showing the dialog with " + << (diffTimestamp(lastRetry, getTimestamp()) / 1000) + << " seconds elapsed.\n" << logofs_flush; + } + #endif + + ESET(reason); + + #ifdef TEST + if (unixPath && unixPath[0] != '\0' ) + { + *logofs << "Loop: Connection to Unix socket file '" + << unixPath << "' failed with error '" + << ESTR() << "'. Retrying.\n" + << logofs_flush; + } + else + { + *logofs << "Loop: Connection to '" << hostName + << ":" << portNum << "' failed with error '" + << ESTR() << "'. Retrying.\n" + << logofs_flush; + } + #endif + } + else + { + // + // Connection was successful. + // + + break; + } + } + + return proxyFD; + +ConnectToRemoteError: + + if (proxyFD != -1) + { + close(proxyFD); + } + + HandleCleanup(); +} + +// +// Make a string of options for the remote +// proxy and write it to the descriptor. +// The string includes the local version. +// + +int SendProxyOptions(int fd) +{ + char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; + + // + // Send the "compatibility" version first, then our + // actual version. Old proxies will take the first + // value and ignore the second. + // + + sprintf(options, "NXPROXY-%s-%i.%i.%i", + control -> NXPROXY_COMPATIBILITY_VERSION, + control -> LocalVersionMajor, + control -> LocalVersionMinor, + control -> LocalVersionPatch); + + // + // If you want to send options from proxy + // initiating the connection use something + // like this: + // + // if (WE_PROVIDE_CREDENTIALS) + // { + // sprintf(options + strlen(options), "%s=%s", option, value); + // } + // + // If you want to send options according to + // local proxy mode use something like this: + // + // if (control -> ProxyMode == proxy_client) + // { + // sprintf(options + strlen(options), "%s=%s", option, value); + // } + // + + // + // Send the authorization cookie if any. We assume + // user can choose to not provide any auth cookie + // and allow any connection to be accepted. + // + + if (WE_PROVIDE_CREDENTIALS && *authCookie != '\0') + { + sprintf(options + strlen(options), " cookie=%s,", authCookie); + } + else + { + sprintf(options + strlen(options), " "); + } + + // + // Now link characteristics and compression + // options. Delta compression, as well as + // preferred pack method, are imposed by + // client proxy. + // + + if (control -> ProxyMode == proxy_client) + { + sprintf(options + strlen(options), "link=%s,pack=%s,cache=%s,", + linkSpeedName, packMethodName, cacheSizeName); + + if (*bitrateLimitName != '\0') + { + sprintf(options + strlen(options), "limit=%s,", + bitrateLimitName); + } + + // + // Let the user disable the render extension + // and let the X client proxy know if it can + // short-circuit the X replies. Also pass + // along the session type to ensure that the + // remote proxy gets the right value. + // + + sprintf(options + strlen(options), "render=%d,taint=%d,", + (control -> HideRender == 0), + control -> TaintReplies); + + if (*sessionType != '\0') + { + sprintf(options + strlen(options), "type=%s,", sessionType); + } + else + { + sprintf(options + strlen(options), "type=default,"); + } + + // + // Add the 'strict' option, if needed. + // + + // Since ProtoStep7 (#issue 108) + if (useStrict != -1) + { + sprintf(options + strlen(options), "strict=%d,", useStrict); + } + + // + // Tell the remote the size of the shared + // memory segment. + // + + // Since ProtoStep7 (#issue 108) + if (*shsegSizeName != '\0') + { + sprintf(options + strlen(options), "shseg=%s,", shsegSizeName); + } + + // + // Send image cache parameters. + // + + sprintf(options + strlen(options), "images=%s,", imagesSizeName); + + sprintf(options + strlen(options), "delta=%d,stream=%d,data=%d ", + control -> LocalDeltaCompression, + control -> LocalStreamCompressionLevel, + control -> LocalDataCompressionLevel); + } + else + { + // + // If no special compression level was selected, + // server side will use compression levels set + // by client. + // + + if (control -> LocalStreamCompressionLevel < 0) + { + sprintf(options + strlen(options), "stream=default,"); + } + else + { + sprintf(options + strlen(options), "stream=%d,", + control -> LocalStreamCompressionLevel); + } + + if (control -> LocalDataCompressionLevel < 0) + { + sprintf(options + strlen(options), "data=default "); + } + else + { + sprintf(options + strlen(options), "data=%d ", + control -> LocalDataCompressionLevel); + } + } + + #ifdef TEST + *logofs << "Loop: Sending remote options '" + << options << "'.\n" << logofs_flush; + #endif + + return WriteLocalData(fd, options, strlen(options)); +} + +int ReadProxyVersion(int fd) +{ + #ifdef TEST + *logofs << "Loop: Going to read the remote proxy version " + << "from FD#" << fd << ".\n" << logofs_flush; + #endif + + // + // Read until the first space in string. + // We expect the remote version number. + // + + char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; + + int result = ReadRemoteData(fd, options, sizeof(options), ' '); + + if (result <= 0) + { + if (result < 0) + { + if (control -> ProxyMode == proxy_server) + { + HandleAlert(ABORT_PROXY_NEGOTIATION_ALERT, 1); + } + + handleAlertInLoop(); + } + + return result; + } + + #ifdef TEST + *logofs << "Loop: Received remote version string '" + << options << "' from FD#" << fd << ".\n" + << logofs_flush; + #endif + + if (strncmp(options, "NXPROXY-", strlen("NXPROXY-")) != 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Parse error in remote options string '" + << options << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Parse error in remote options string '" + << options << "'.\n"; + + return -1; + } + + // + // Try to determine if this is a pre-2.0.0 + // version advertising itself as compatible + // with the 1.2.2. + // + + int major = -1; + int minor = -1; + int patch = -1; + + sscanf(options, "NXPROXY-%i.%i.%i-%i.%i.%i", &(control -> RemoteVersionMajor), + &(control -> RemoteVersionMinor), &(control -> RemoteVersionPatch), + &major, &minor, &patch); + + if (control -> RemoteVersionMajor == 1 && + control -> RemoteVersionMinor == 2 && + control -> RemoteVersionPatch == 2 && + major != -1 && minor != -1 && patch != -1) + { + #ifdef TEST + *logofs << "Loop: Read trailing remote version '" << major + << "." << minor << "." << patch << "'.\n" + << logofs_flush; + #endif + + control -> CompatVersionMajor = major; + control -> CompatVersionMinor = minor; + control -> CompatVersionPatch = patch; + + control -> RemoteVersionMajor = major; + control -> RemoteVersionMinor = minor; + control -> RemoteVersionPatch = patch; + } + else + { + // + // We read the remote version at the first + // round. If the second version is missing, + // we will retain the values read before. + // + + sscanf(options, "NXPROXY-%i.%i.%i-%i.%i.%i", &(control -> CompatVersionMajor), + &(control -> CompatVersionMinor), &(control -> CompatVersionPatch), + &(control -> RemoteVersionMajor), &(control -> RemoteVersionMinor), + &(control -> RemoteVersionPatch)); + } + + *logofs << "Loop: Identified remote version '" << control -> RemoteVersionMajor + << "." << control -> RemoteVersionMinor << "." << control -> RemoteVersionPatch + << "'.\n" << logofs_flush; + + *logofs << "Loop: Remote compatibility version '" << control -> CompatVersionMajor + << "." << control -> CompatVersionMinor << "." << control -> CompatVersionPatch + << "'.\n" << logofs_flush; + + *logofs << "Loop: Local version '" << control -> LocalVersionMajor + << "." << control -> LocalVersionMinor << "." << control -> LocalVersionPatch + << "'.\n" << logofs_flush; + + if (SetVersion() < 0) + { + if (control -> ProxyMode == proxy_server) + { + HandleAlert(WRONG_PROXY_VERSION_ALERT, 1); + } + + handleAlertInLoop(); + + return -1; + } + + return 1; +} + +int ReadProxyOptions(int fd) +{ + #ifdef TEST + *logofs << "Loop: Going to read the remote proxy options " + << "from FD#" << fd << ".\n" << logofs_flush; + #endif + + char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; + + int result = ReadRemoteData(fd, options, sizeof(options), ' '); + + if (result <= 0) + { + return result; + } + + #ifdef TEST + *logofs << "Loop: Received remote options string '" + << options << "' from FD#" << fd << ".\n" + << logofs_flush; + #endif + + // + // Get the remote options, delimited by a space character. + // Note that there will be a further initialization phase + // at the time proxies negotiate cache file to restore. + // + + if (ParseRemoteOptions(options) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Couldn't negotiate a valid " + << "session with remote NX proxy.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Couldn't negotiate a valid " + << "session with remote NX proxy.\n"; + + return -1; + } + + return 1; +} + +int SendProxyCaches(int fd) +{ + #ifdef TEST + *logofs << "Loop: Synchronizing local and remote caches.\n" + << logofs_flush; + #endif + + if (control -> ProxyMode == proxy_client) + { + // + // Prepare a list of caches matching this + // session type and send it to the remote. + // + + #ifdef TEST + *logofs << "Loop: Going to send the list of local caches.\n" + << logofs_flush; + #endif + + SetCaches(); + + int entries = DEFAULT_REMOTE_CACHE_ENTRIES; + + const char prefix = 'C'; + + if (control -> LocalDeltaCompression == 0 || + control -> PersistentCacheEnableLoad == 0) + { + #ifdef TEST + *logofs << "Loop: Writing an empty list to FD#" << fd + << ".\n" << logofs_flush; + #endif + + return WriteLocalData(fd, "cachelist=none ", strlen("cachelist=none ")); + } + + int count = 0; + + #ifdef TEST + *logofs << "Loop: Looking for cache files in directory '" + << control -> PersistentCachePath << "'.\n" << logofs_flush; + #endif + + DIR *cacheDir = opendir(control -> PersistentCachePath); + + if (cacheDir != NULL) + { + dirent *dirEntry; + + int prologue = 0; + + while (((dirEntry = readdir(cacheDir)) != NULL) && (count < entries)) + { + if (*dirEntry -> d_name == prefix && + strlen(dirEntry -> d_name) == (MD5_LENGTH * 2 + 2)) + { + if (prologue == 0) + { + WriteLocalData(fd, "cachelist=", strlen("cachelist=")); + + prologue = 1; + } + else + { + WriteLocalData(fd, ",", strlen(",")); + } + + #ifdef TEST + *logofs << "Loop: Writing entry '" << control -> PersistentCachePath + << "/" << dirEntry -> d_name << "' to FD#" << fd + << ".\n" << logofs_flush; + #endif + + // + // Write cache file name to the socket, + // including leading 'C-' or 'S-'. + // + + WriteLocalData(fd, dirEntry -> d_name, MD5_LENGTH * 2 + 2); + + count++; + } + } + + closedir(cacheDir); + } + + if (count == 0) + { + #ifdef TEST + *logofs << "Loop: Writing an empty list to FD#" << fd + << ".\n" << logofs_flush; + #endif + + return WriteLocalData(fd, "cachelist=none ", strlen("cachelist=none ")); + } + else + { + return WriteLocalData(fd, " ", 1); + } + } + else + { + // + // Send back the selected cache name. + // + + #ifdef TEST + *logofs << "Loop: Going to send the selected cache.\n" + << logofs_flush; + #endif + + char buffer[DEFAULT_STRING_LENGTH]; + + if (control -> PersistentCacheName != NULL) + { + #ifdef TEST + *logofs << "Loop: Name of selected cache file is '" + << control -> PersistentCacheName << "'.\n" + << logofs_flush; + #endif + + sprintf(buffer, "cachefile=%s%s ", + *(control -> PersistentCacheName) == 'C' ? "S-" : "C-", + control -> PersistentCacheName + 2); + } + else + { + #ifdef TEST + *logofs << "Loop: No valid cache file was selected.\n" + << logofs_flush; + #endif + + sprintf(buffer, "cachefile=none "); + } + + #ifdef TEST + *logofs << "Loop: Sending string '" << buffer + << "' as selected cache file.\n" + << logofs_flush; + #endif + + return WriteLocalData(fd, buffer, strlen(buffer)); + } +} + +int ReadProxyCaches(int fd) +{ + if (control -> ProxyMode == proxy_client) + { + #ifdef TEST + *logofs << "Loop: Going to receive the selected proxy cache.\n" + << logofs_flush; + #endif + + // + // We will read the name of cache plus the stop character. + // + + char buffer[DEFAULT_STRING_LENGTH]; + + // + // Leave space for a trailing null. + // + + int result = ReadRemoteData(fd, buffer, sizeof("cachefile=") + MD5_LENGTH * 2 + 3, ' '); + + if (result <= 0) + { + return result; + } + + char *cacheName = strstr(buffer, "cachefile="); + + if (cacheName == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid cache file option '" + << buffer << "' provided by remote proxy.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Invalid cache file option '" + << buffer << "' provided by remote proxy.\n"; + + HandleCleanup(); + } + + cacheName += strlen("cachefile="); + + if (control -> PersistentCacheName != NULL) + { + delete [] control -> PersistentCacheName; + } + + control -> PersistentCacheName = NULL; + + if (strncasecmp(cacheName, "none", strlen("none")) == 0) + { + #ifdef TEST + *logofs << "Loop: No cache file selected by remote proxy.\n" + << logofs_flush; + #endif + } + else if (strlen(cacheName) != MD5_LENGTH * 2 + 3 || + *(cacheName + MD5_LENGTH * 2 + 2) != ' ') + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid cache file name '" + << cacheName << "' provided by remote proxy.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Invalid cache file name '" + << cacheName << "' provided by remote proxy.\n"; + + HandleCleanup(); + } + else + { + // + // It is "C-" + 32 + "\0". + // + + control -> PersistentCacheName = new char[MD5_LENGTH * 2 + 3]; + + *(cacheName + MD5_LENGTH * 2 + 2) = '\0'; + + strcpy(control -> PersistentCacheName, cacheName); + + #ifdef TEST + *logofs << "Loop: Cache file '" << control -> PersistentCacheName + << "' selected by remote proxy.\n" << logofs_flush; + #endif + } + } + else + { + #ifdef TEST + *logofs << "Loop: Going to receive the list of remote caches.\n" + << logofs_flush; + #endif + + SetCaches(); + + int size = ((MD5_LENGTH * 2 + 2) + strlen(",")) * DEFAULT_REMOTE_CACHE_ENTRIES + + strlen("cachelist=") + strlen(" ") + 1; + + char *buffer = new char[size]; + + int result = ReadRemoteData(fd, buffer, size - 1, ' '); + + if (result <= 0) + { + delete [] buffer; + + return result; + } + + #ifdef TEST + *logofs << "Loop: Read list of caches from remote side as '" + << buffer << "'.\n" << logofs_flush; + #endif + + // + // Prepare the buffer. What we want is a list + // like "cache1,cache2,cache2" terminated by + // null. + // + + *(buffer + strlen(buffer) - 1) = '\0'; + + if (strncasecmp(buffer, "cachelist=", strlen("cachelist=")) != 0) + { + #ifdef PANIC + *logofs << "Loop: Wrong format for list of cache files " + << "read from FD#" << fd << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Wrong format for list of cache files.\n"; + + delete [] buffer; + + return -1; + } + + control -> PersistentCacheName = GetLastCache(buffer, control -> PersistentCachePath); + + // + // Get rid of list of caches. + // + + delete [] buffer; + } + + return 1; +} + +int ReadForwarderVersion(int fd) +{ + #ifdef TEST + *logofs << "Loop: Going to negotiate the forwarder version.\n" + << logofs_flush; + #endif + + // + // Check if we actually expect the session cookie. + // + + if (*authCookie == '\0') + { + #ifdef TEST + *logofs << "Loop: No authentication cookie required " + << "from FD#" << fd << ".\n" << logofs_flush; + #endif + + return 1; + } + + char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; + + int result = ReadRemoteData(fd, options, sizeof(options), ' '); + + if (result <= 0) + { + return result; + } + + #ifdef TEST + *logofs << "Loop: Received forwarder version string '" << options + << "' from FD#" << fd << ".\n" << logofs_flush; + #endif + + if (strncmp(options, "NXSSH-", strlen("NXSSH-")) != 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Parse error in forwarder options string '" + << options << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Parse error in forwarder options string '" + << options << "'.\n"; + + return -1; + } + + // + // Accept whatever forwarder version. + // + + sscanf(options, "NXSSH-%i.%i.%i", &(control -> RemoteVersionMajor), + &(control -> RemoteVersionMinor), &(control -> RemoteVersionPatch)); + + #ifdef TEST + *logofs << "Loop: Read forwarder version '" << control -> RemoteVersionMajor + << "." << control -> RemoteVersionMinor << "." << control -> RemoteVersionPatch + << "'.\n" << logofs_flush; + #endif + + return 1; +} + +int ReadForwarderOptions(int fd) +{ + // + // Get the forwarder cookie. + // + + if (*authCookie == '\0') + { + #ifdef TEST + *logofs << "Loop: No authentication cookie required " + << "from FD#" << fd << ".\n" << logofs_flush; + #endif + + return 1; + } + + char options[DEFAULT_REMOTE_OPTIONS_LENGTH]; + + int result = ReadRemoteData(fd, options, sizeof(options), ' '); + + if (result <= 0) + { + return result; + } + + #ifdef TEST + *logofs << "Loop: Received forwarder options string '" + << options << "' from FD#" << fd << ".\n" + << logofs_flush; + #endif + + if (ParseForwarderOptions(options) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Couldn't negotiate a valid " + << "cookie with the NX forwarder.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Couldn't negotiate a valid " + << "cookie with the NX forwarder.\n"; + + return -1; + } + + return 1; +} + +int ReadRemoteData(int fd, char *buffer, int size, char stop) +{ + #ifdef TEST + *logofs << "Loop: Going to read remote data from FD#" + << fd << ".\n" << logofs_flush; + #endif + + if (size >= MAXIMUM_REMOTE_OPTIONS_LENGTH) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Maximum remote options buffer " + << "limit exceeded.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Maximum remote options buffer " + << "limit exceeded.\n"; + + HandleCleanup(); + } + + while (remotePosition < (size - 1)) + { + int result = read(fd, remoteData + remotePosition, 1); + + getNewTimestamp(); + + if (result <= 0) + { + if (result == -1) + { + if (EGET() == EAGAIN) + { + #ifdef TEST + *logofs << "Loop: Reading data from FD#" << fd + << " would block.\n" << logofs_flush; + #endif + + return 0; + } + else if (EGET() == EINTR) + { + if (CheckAbort() != 0) + { + return -1; + } + + continue; + } + } + + #ifdef PANIC + *logofs << "Loop: PANIC! The remote NX proxy closed " + << "the connection.\n" << logofs_flush; + #endif + + cerr << "Error" << ": The remote NX proxy closed " + << "the connection.\n"; + + return -1; + } + else if (*(remoteData + remotePosition) == stop) + { + #ifdef TEST + *logofs << "Loop: Read stop character from FD#" + << fd << ".\n" << logofs_flush; + #endif + + remotePosition++; + + // + // Copy the fake terminating null + // in the buffer. + // + + *(remoteData + remotePosition) = '\0'; + + memcpy(buffer, remoteData, remotePosition + 1); + + #ifdef TEST + *logofs << "Loop: Remote string '" << remoteData + << "' read from FD#" << fd << ".\n" + << logofs_flush; + #endif + + int t = remotePosition; + + remotePosition = 0; + + return t; + } + else + { + // + // Make sure string received + // from far end is printable. + // + + if (isgraph(*(remoteData + remotePosition)) == 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Non printable character decimal '" + << (unsigned int) *(remoteData + remotePosition) + << "' received in remote data from FD#" + << fd << ".\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Non printable character decimal '" + << (unsigned int) *(remoteData + remotePosition) + << "' received in remote data from FD#" + << fd << ".\n" << logofs_flush; + + *(remoteData + remotePosition) = ' '; + } + + #ifdef DEBUG + *logofs << "Loop: Read a further character " + << "from FD#" << fd << ".\n" + << logofs_flush; + #endif + + remotePosition++; + } + } + + *(remoteData + remotePosition) = '\0'; + + #ifdef PANIC + *logofs << "Loop: PANIC! Stop character missing " + << "from FD#" << fd << " after " << remotePosition + << " characters read in string '" << remoteData + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Stop character missing " + << "from FD#" << fd << " after " << remotePosition + << " characters read in string '" << remoteData + << "'.\n"; + + memcpy(buffer, remoteData, remotePosition); + + remotePosition = 0; + + return -1; +} + +static int +hexval(char c) { + if ((c >= '0') && (c <= '9')) + return c - '0'; + if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + return -1; +} + +static void +URLDecodeInPlace(char *str) { + if (str) { + char *to = str; + while (str[0]) { + if ((str[0] == '%') && + (hexval(str[1]) >= 0) && + (hexval(str[2]) >= 0)) { + *(to++) = hexval(str[1]) * 16 + hexval(str[2]); + str += 3; + } + else + *(to++) = *(str++); + } + *to = '\0'; + } +} + +int WriteLocalData(int fd, const char *buffer, int size) +{ + int position = 0; + int ret = 0; + fd_set writeSet; + struct timeval selectTs = {30, 0}; + + while (position < size) + { + + // A write to a non-blocking socket may fail with EAGAIN. The problem is + // that cache data is done in several writes, and there's no easy way + // to handle failure without rewriting a significant amount of code. + // + // Bailing out of the outer loop would result in restarting the sending + // of the entire cache list, which would confuse the other side. + + FD_ZERO(&writeSet); + FD_SET(fd, &writeSet); + + ret = select(fd+1, NULL, &writeSet, NULL, &selectTs); + + #ifdef DEBUG + *logofs << "Loop: WriteLocalData: select() returned with a code of " << ret << " and remaining timeout of " + << selectTs.tv_sec << " sec, " << selectTs.tv_usec << "usec\n" << logofs_flush; + #endif + + if ( ret < 0 ) + { + *logofs << "Loop: Error in select() when writing data to FD#" << fd << ": " << strerror(EGET()) << "\n" << logofs_flush; + + if ( EGET() == EINTR ) + continue; + + return -1; + } + else if ( ret == 0 ) + { + *logofs << "Loop: Timeout expired in select() when writing data to FD#" << fd << ": " << strerror(EGET()) << "\n" << logofs_flush; + return -1; + } + + int result = write(fd, buffer + position, size - position); + + getNewTimestamp(); + + if (result <= 0) + { + if (result < 0 && (EGET() == EINTR || EGET() == EAGAIN || EGET() == EWOULDBLOCK)) + { + continue; + } + + #ifdef TEST + *logofs << "Loop: Error writing data to FD#" + << fd << ".\n" << logofs_flush; + #endif + + return -1; + } + + position += result; + } + + return position; +} + +// +// Parse the string passed by calling process in +// the environment. This is not necessarily the +// content of DISPLAY variable, but can be the +// parameters passed when creating the process +// or thread. +// + +int ParseEnvironmentOptions(const char *env, int force) +{ + // + // Be sure log file is valid. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + // + // Be sure we have a parameters repository + // and a context to jump into because this + // can be called before creating the proxy. + // + + if (control == NULL) + { + control = new Control(); + } + + if (setjmp(context) == 1) + { + #ifdef TEST + *logofs << "Loop: Out of the long jump while parsing " + << "the environment options.\n" + << logofs_flush; + #endif + + return -1; + } + + if (force == 0 && parsedOptions == 1) + { + #ifdef TEST + *logofs << "Loop: Skipping a further parse of environment " + << "options string '" << (env != NULL ? env : "") + << "'.\n" << logofs_flush; + #endif + + return 1; + } + + if (env == NULL || *env == '\0') + { + #ifdef TEST + *logofs << "Loop: Nothing to do with empty environment " + << "options string '" << (env != NULL ? env : "") + << "'.\n" << logofs_flush; + #endif + + return 0; + } + + #ifdef TEST + *logofs << "Loop: Going to parse the environment options " + << "string '" << env << "'.\n" + << logofs_flush; + #endif + + parsedOptions = 1; + + // + // Copy the string passed as parameter + // because we need to modify it. + // + + char opts[DEFAULT_DISPLAY_OPTIONS_LENGTH]; + + #ifdef VALGRIND + + memset(opts, '\0', DEFAULT_DISPLAY_OPTIONS_LENGTH); + + #endif + + if (strlen(env) >= DEFAULT_DISPLAY_OPTIONS_LENGTH) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Environment options string '" << env + << "' exceeds length of " << DEFAULT_DISPLAY_OPTIONS_LENGTH + << " characters.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Environment options string '" << env + << "' exceeds length of " << DEFAULT_DISPLAY_OPTIONS_LENGTH + << " characters.\n"; + + return -1; + } + + strcpy(opts, env); + + char *nextOpts = opts; + + // + // Ensure that DISPLAY environment variable + // (roughly) follows the X convention for + // transport notation. + // + + if (strncasecmp(opts, "nx/nx,:", 7) == 0 || + strncasecmp(opts, "nx,:", 4) == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Parse error in options string '" + << opts << "' at 'nx,:'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Parse error in options string '" + << opts << "' at 'nx,:'.\n"; + + return -1; + } + else if (strncasecmp(opts, "nx/nx,", 6) == 0) + { + nextOpts += 6; + } + else if (strncasecmp(opts, "nx,", 3) == 0) + { + nextOpts += 3; + } + else if (strncasecmp(opts, "nx:", 3) == 0) + { + nextOpts += 3; + } + else if (force == 0) + { + #ifdef TEST + *logofs << "Loop: Ignoring host X server display string '" + << opts << "'.\n" << logofs_flush; + #endif + + return 0; + } + + // + // Save here the name of the options file and + // parse it after all the other options. + // + + char fileOptions[DEFAULT_STRING_LENGTH] = { 0 }; + + // + // The options string is intended to be a series + // of name/value tuples in the form name=value + // separated by the ',' character ended by a ':' + // followed by remote NX proxy port. + // + + char *name; + char *value; + + value = strrchr(nextOpts, ':'); + + if (value != NULL) + { + char *check = value + 1; + + if (*check == '\0' || isdigit(*check) == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify NX port in string '" + << value << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify NX port in string '" + << value << "'.\n"; + + return -1; + } + + proxyPort = atoi(check); + + // + // Get rid of the port specification. + // + + *value = '\0'; + } + else if (proxyPort == DEFAULT_NX_PROXY_PORT && force == 0) + { + // + // Complain only if user didn't specify + // the port on the command line. + // + + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify NX port in string '" + << opts << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify NX port in string '" + << opts << "'.\n"; + + return -1; + } + + #ifdef TEST + *logofs << "Loop: Parsing options string '" + << nextOpts << "'.\n" << logofs_flush; + #endif + + // + // Now all the other optional parameters. + // + + name = strtok(nextOpts, "="); + + char connectHost[DEFAULT_STRING_LENGTH] = { 0 }; + long connectPort = -1; + + while (name) + { + value = strtok(NULL, ","); + URLDecodeInPlace(value); + + if (CheckArg("environment", name, value) < 0) + { + return -1; + } + + if (strcasecmp(name, "options") == 0) + { + strncpy(fileOptions, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "display") == 0) + { + strncpy(displayHost, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "link") == 0) + { + + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else if (ParseLinkOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify 'link' option in string '" + << value << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify 'link' option in string '" + << value << "'.\n"; + if (ParseLinkOption("adsl") < 0) + return -1; + } + } + else if (strcasecmp(name, "limit") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else if (ParseBitrateOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify option 'limit' in string '" + << value << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify option 'limit' in string '" + << value << "'.\n"; + + return -1; + } + } + else if (strcasecmp(name, "type") == 0) + { + // + // Type of session, for example "desktop", + // "application", "windows", etc. + // + + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else + { + if (strcasecmp(value, "default") == 0) + { + *sessionType = '\0'; + } + else + { + strncpy(sessionType, value, DEFAULT_STRING_LENGTH - 1); + } + } + } + else if (strcasecmp(name, "listen") == 0) + { + char *socketUri = NULL; + if (connectSocket.getSpec(&socketUri)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't handle 'listen' and 'connect' parameters " + << "at the same time.\n" << logofs_flush; + + *logofs << "Loop: PANIC! Refusing 'listen' parameter with 'connect' being '" + << socketUri << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't handle 'listen' and 'connect' parameters " + << "at the same time.\n"; + + cerr << "Error" << ": Refusing 'listen' parameter with 'connect' being '" + << socketUri << "'.\n"; + + free(socketUri); + return -1; + } + + SetAndValidateChannelEndPointArg("local", name, value, listenSocket); + + } + else if (strcasecmp(name, "loopback") == 0) + { + loopbackBind = ValidateArg("local", name, value); + } + else if (strcasecmp(name, "accept") == 0) + { + char *socketUri = NULL; + if (connectSocket.getSpec(&socketUri)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't handle 'accept' and 'connect' parameters " + << "at the same time.\n" << logofs_flush; + + *logofs << "Loop: PANIC! Refusing 'accept' parameter with 'connect' being '" + << socketUri << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't handle 'accept' and 'connect' parameters " + << "at the same time.\n"; + + cerr << "Error" << ": Refusing 'accept' parameter with 'connect' being '" + << socketUri << "'.\n"; + + free(socketUri); + return -1; + } + + strncpy(acceptHost, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "connect") == 0) + { + if (*acceptHost != '\0') + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't handle 'connect' and 'accept' parameters " + << "at the same time.\n" << logofs_flush; + + *logofs << "Loop: PANIC! Refusing 'connect' parameter with 'accept' being '" + << acceptHost << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't handle 'connect' and 'accept' parameters " + << "at the same time.\n"; + + cerr << "Error" << ": Refusing 'connect' parameter with 'accept' being '" + << acceptHost << "'.\n"; + + return -1; + } + if ((strncmp(value, "tcp:", 4) == 0) || (strncmp(value, "unix:", 5) == 0)) + SetAndValidateChannelEndPointArg("local", name, value, connectSocket); + else + // if the "connect" parameter does not start with "unix:" or "tcp:" assume + // old parameter usage style (providing hostname string only). + strcpy(connectHost, value); + } + else if (strcasecmp(name, "port") == 0) + { + connectPort = ValidateArg("local", name, value); + } + else if (strcasecmp(name, "retry") == 0) + { + control -> OptionProxyRetryConnect = ValidateArg("local", name, value); + control -> OptionServerRetryConnect = ValidateArg("local", name, value); + } + else if (strcasecmp(name, "session") == 0) + { + strncpy(sessionFileName, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "errors") == 0) + { + // + // The old name of the parameter was 'log' + // but the default name for the file is + // 'errors' so it is more logical to use + // the same name. + // + + strncpy(errorsFileName, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "root") == 0) + { + strncpy(rootDir, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "id") == 0) + { + strncpy(sessionId, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "stats") == 0) + { + control -> EnableStatistics = 1; + + strncpy(statsFileName, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "cookie") == 0) + { + LowercaseArg("local", name, value); + + strncpy(authCookie, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "nodelay") == 0) + { + useNoDelay = ValidateArg("local", name, value); + } + else if (strcasecmp(name, "policy") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else + { + usePolicy = ValidateArg("local", name, value); + } + } + else if (strcasecmp(name, "render") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else + { + useRender = ValidateArg("local", name, value); + } + } + else if (strcasecmp(name, "taint") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else + { + useTaint = ValidateArg("local", name, value); + } + } + else if (strcasecmp(name, "delta") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else + { + control -> LocalDeltaCompression = ValidateArg("local", name, value); + } + } + else if (strcasecmp(name, "data") == 0) + { + control -> LocalDataCompressionLevel = ValidateArg("local", name, value); + + if (control -> LocalDataCompressionLevel == 0) + { + control -> LocalDataCompression = 0; + } + else + { + control -> LocalDataCompression = 1; + } + } + else if (strcasecmp(name, "stream") == 0) + { + control -> LocalStreamCompressionLevel = ValidateArg("local", name, value); + + if (control -> LocalStreamCompressionLevel == 0) + { + control -> LocalStreamCompression = 0; + } + else + { + control -> LocalStreamCompression = 1; + } + } + else if (strcasecmp(name, "memory") == 0) + { + control -> LocalMemoryLevel = ValidateArg("local", name, value); + } + else if (strcasecmp(name, "cache") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else if (ParseCacheOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify cache size for string '" + << value << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify cache size for string '" + << value << "'.\n"; + + return -1; + } + } + else if (strcasecmp(name, "images") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else if (ParseImagesOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify images cache size for string '" + << value << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify images cache size for string '" + << value << "'.\n"; + + return -1; + } + } + else if (strcasecmp(name, "shseg") == 0) + { + // + // The 'shmem' option is used by the agent, together + // with 'shpix' literal. We make the 'shseg' option + // specific to the proxy and use it to determine the + // size of the shared memory segment, or otherwise 0, + // if the use of the shared memory extension should + // not be enabled on the real X server. + // + + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else if (ParseShmemOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify size of shared memory " + << "segment in string '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify size of shared memory " + << "segment in string '" << value << "'.\n"; + + return -1; + } + } + else if (strcasecmp(name, "load") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else + { + control -> PersistentCacheEnableLoad = ValidateArg("local", name, value); + + if (control -> PersistentCacheEnableLoad > 0) + { + control -> PersistentCacheEnableLoad = 1; + } + else + { + if (control -> PersistentCacheName != NULL) + { + delete [] control -> PersistentCacheName; + } + + control -> PersistentCacheName = NULL; + + control -> PersistentCacheEnableLoad = 0; + } + } + } + else if (strcasecmp(name, "save") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else + { + control -> PersistentCacheEnableSave = ValidateArg("local", name, value); + + if (control -> PersistentCacheEnableSave > 0) + { + control -> PersistentCacheEnableSave = 1; + } + else + { + if (control -> PersistentCacheName != NULL) + { + delete [] control -> PersistentCacheName; + } + + control -> PersistentCacheName = NULL; + + control -> PersistentCacheEnableSave = 0; + } + } + } + else if (strcasecmp(name, "cups") == 0) + { + SetAndValidateChannelEndPointArg("local", name, value, cupsPort); + } + else if (strcasecmp(name, "sync") == 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! No 'sync' channel in current version. " + << "Assuming 'cups' channel.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": No 'sync' channel in current version. " + << "Assuming 'cups' channel.\n"; + + SetAndValidateChannelEndPointArg("local", name, value, cupsPort); + } + else if (strcasecmp(name, "keybd") == 0 || + strcasecmp(name, "aux") == 0) + { + SetAndValidateChannelEndPointArg("local", name, value, auxPort); + } + else if (strcasecmp(name, "samba") == 0 || + strcasecmp(name, "smb") == 0) + { + SetAndValidateChannelEndPointArg("local", name, value, smbPort); + } + else if (strcasecmp(name, "media") == 0) + { + SetAndValidateChannelEndPointArg("local", name, value, mediaPort); + } + else if (strcasecmp(name, "http") == 0) + { + SetAndValidateChannelEndPointArg("local", name, value, httpPort); + } + else if (strcasecmp(name, "font") == 0) + { + strncpy(fontPort, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "slave") == 0) + { + SetAndValidateChannelEndPointArg("local", name, value, slavePort); + } + else if (strcasecmp(name, "mask") == 0) + { + control -> ChannelMask = ValidateArg("local", name, value); + } + else if (strcasecmp(name, "timeout") == 0) + { + int timeout = ValidateArg("local", name, value); + + if (timeout == 0) + { + #ifdef TEST + *logofs << "Loop: Disabling timeout on broken " + << "proxy connection.\n" << logofs_flush; + #endif + + control -> ProxyTimeout = 0; + } + else + { + control -> ProxyTimeout = timeout * 1000; + } + } + else if (strcasecmp(name, "cleanup") == 0) + { + int cleanup = ValidateArg("local", name, value); + + if (cleanup == 0) + { + #ifdef TEST + *logofs << "Loop: Disabling grace timeout on " + << "proxy shutdown.\n" << logofs_flush; + #endif + + control -> CleanupTimeout = 0; + } + else + { + control -> CleanupTimeout = cleanup * 1000; + } + } + else if (strcasecmp(name, "pack") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else if (ParsePackOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify pack method for string '" + << value << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify pack method for string '" + << value << "'.\n"; + if (ParsePackOption("nopack")<0) + return -1; + } + } + else if (strcasecmp(name, "core") == 0) + { + control -> EnableCoreDumpOnAbort = ValidateArg("local", name, value); + } + else if (strcasecmp(name, "kill") == 0) + { + if (control -> KillDaemonOnShutdownNumber < + control -> KillDaemonOnShutdownLimit) + { + #ifdef TEST + *logofs << "Loop: WARNING! Adding process with pid '" + << ValidateArg("local", name, value) << " to the " + << "daemons to kill at shutdown.\n" + << logofs_flush; + #endif + + control -> KillDaemonOnShutdown[control -> + KillDaemonOnShutdownNumber] = + ValidateArg("local", name, value); + + control -> KillDaemonOnShutdownNumber++; + } + else + { + #ifdef WARNING + *logofs << "Loop: WARNING! Number of daemons to kill " + << "at shutdown exceeded.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Number of daemons to kill " + << "at shutdown exceeded.\n"; + } + } + else if (strcasecmp(name, "strict") == 0) + { + if (control -> ProxyMode == proxy_server) + { + PrintOptionIgnored("local", name, value); + } + else + { + useStrict = ValidateArg("local", name, value); + } + } + else if (strcasecmp(name, "encryption") == 0) + { + useEncryption = ValidateArg("local", name, value); + } + else if (strcasecmp(name, "product") == 0) + { + strncpy(productName, value, DEFAULT_STRING_LENGTH - 1); + } + else if (strcasecmp(name, "rootless") == 0 || + strcasecmp(name, "geometry") == 0 || + strcasecmp(name, "resize") == 0 || + strcasecmp(name, "fullscreen") == 0 || + strcasecmp(name, "keyboard") == 0 || + strcasecmp(name, "clipboard") == 0 || + strcasecmp(name, "streaming") == 0 || + strcasecmp(name, "backingstore") == 0 || + strcasecmp(name, "sleep") == 0 || + strcasecmp(name, "tolerancechecks") == 0) + { + #ifdef DEBUG + *logofs << "Loop: Ignoring agent option '" << name + << "' with value '" << value << "'.\n" + << logofs_flush; + #endif + } + else if (strcasecmp(name, "composite") == 0 || + strcasecmp(name, "shmem") == 0 || + strcasecmp(name, "shpix") == 0 || + strcasecmp(name, "kbtype") == 0 || + strcasecmp(name, "client") == 0 || + strcasecmp(name, "shadow") == 0 || + strcasecmp(name, "shadowuid") == 0 || + strcasecmp(name, "shadowmode") == 0 || + strcasecmp(name, "clients") == 0 || + strcasecmp(name, "xinerama") == 0) + { + #ifdef DEBUG + *logofs << "Loop: Ignoring agent option '" << name + << "' with value '" << value << "'.\n" + << logofs_flush; + #endif + } + else if (strcasecmp(name, "defer") == 0 || + strcasecmp(name, "tile") == 0 || + strcasecmp(name, "menu") == 0 || + strcasecmp(name, "state") == 0 ) + { + #ifdef DEBUG + *logofs << "Loop: Ignoring agent option '" << name + << "' with value '" << value << "'.\n" + << logofs_flush; + #endif + } + else + { + #ifdef WARNING + *logofs << "Loop: WARNING! Ignoring unknown option '" + << name << "' with value '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Ignoring unknown option '" + << name << "' with value '" << value << "'.\n"; + } + + name = strtok(NULL, "="); + + } // End of while (name) ... + + // Assemble the connectSocket channel end point if parameter values have been old-school... + if (connectSocket.disabled() && (connectHost[0] != '\0') && (proxyPort > 0 || connectPort > 0)) + { + if (connectPort < 0) + connectPort = proxyPort + DEFAULT_NX_PROXY_PORT_OFFSET; + + char tcpHostAndPort[DEFAULT_STRING_LENGTH] = { 0 }; + sprintf(tcpHostAndPort, "tcp:%s:%ld", connectHost, connectPort); + SetAndValidateChannelEndPointArg("local", name, tcpHostAndPort, connectSocket); + } + + #ifdef TEST + *logofs << "Loop: Completed parsing of string '" + << env << "'.\n" << logofs_flush; + #endif + + if ((*fileOptions != '\0') && (strncmp(fileOptions, "/dev/", 5) != 0) && (strncmp(fileOptions, "/proc/", 6) != 0) && (strncmp(fileOptions, "/sys/", 5) != 0)) + { + if (strcmp(fileOptions, optionsFileName) != 0) + { + #ifdef TEST + *logofs << "Loop: Reading options from '" << fileOptions + << "'.\n" << logofs_flush; + #endif + + if (ParseFileOptions(fileOptions) < 0) + { + return -1; + } + } + #ifdef WARNING + else + { + *logofs << "Loop: WARNING! Name of the options file " + << "specified multiple times. Not parsing " + << "again.\n" << logofs_flush; + } + #endif + + if (*optionsFileName == '\0') + { + strncpy(optionsFileName, value, DEFAULT_STRING_LENGTH - 1); + + #ifdef TEST + *logofs << "Loop: Assuming name of options file '" + << optionsFileName << "'.\n" + << logofs_flush; + #endif + } + } + + // + // If port where proxy is acting as an X server + // was not specified assume the same port where + // proxy is listening for the remote peer. + // + + if (xPort == DEFAULT_NX_X_PORT) + { + xPort = proxyPort; + } + + return 1; +} + +// +// Parse the command line options passed by user when +// running proxy in stand alone mode. Note that passing +// parameters this way is strongly discouraged. These +// command line switch can change (and they do often). +// Please, use the form "option=value" instead and set +// the DISPLAY environment variable. +// + +int ParseCommandLineOptions(int argc, const char **argv) +{ + // + // Be sure log file is valid. + // + + if (logofs == NULL) + { + logofs = &cerr; + } + + if (setjmp(context) == 1) + { + #ifdef TEST + *logofs << "Loop: Out of the long jump while parsing " + << "the command line options.\n" + << logofs_flush; + #endif + + return -1; + } + + // + // Be sure we have a parameters repository + // + + if (control == NULL) + { + control = new Control(); + } + + if (parsedCommand == 1) + { + #ifdef TEST + *logofs << "Loop: Skipping a further parse of command line options.\n" + << logofs_flush; + #endif + + return 1; + } + + #ifdef TEST + *logofs << "Loop: Going to parse the command line options.\n" + << logofs_flush; + #endif + + parsedCommand = 1; + + // + // Print out arguments. + // + + #ifdef TEST + + *logofs << "Loop: Argc is " << argc << ".\n" << logofs_flush; + + for (int argi = 0; argi < argc; argi++) + { + *logofs << "Loop: Argv[" << argi << "] is " << argv[argi] + << ".\n" << logofs_flush; + } + + #endif + + // + // Shall use getopt here. + // + + for (int argi = 1; argi < argc; argi++) + { + const char *nextArg = argv[argi]; + + if (*nextArg == '-') + { + switch (*(nextArg + 1)) + { + case 'h': + { + PrintUsageInfo(nextArg, 0); + + return -1; + } + case 'C': + { + // + // Start proxy in CLIENT mode. + // + + if (WE_SET_PROXY_MODE == 0) + { + #ifdef TEST + *logofs << "Loop: Setting local proxy mode to proxy_client.\n" + << logofs_flush; + #endif + + control -> ProxyMode = proxy_client; + } + else if (control -> ProxyMode != proxy_client) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't redefine local proxy to " + << "client mode.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't redefine local proxy to " + << "client mode.\n"; + + return -1; + } + + break; + } + case 'S': + { + // + // Start proxy in SERVER mode. + // + + if (WE_SET_PROXY_MODE == 0) + { + #ifdef TEST + *logofs << "Loop: Setting local proxy mode to proxy_server.\n" + << logofs_flush; + #endif + + control -> ProxyMode = proxy_server; + } + else if (control -> ProxyMode != proxy_server) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't redefine local proxy to " + << "server mode.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't redefine local proxy to " + << "server mode.\n"; + + return -1; + } + + break; + } + case 'v': + { + PrintVersionInfo(); + + return -1; + } + default: + { + PrintUsageInfo(nextArg, 1); + + // + // Function GetArg() is not used anymore. + // Add a dummy call to avoid the warning. + // + + if (0) + { + GetArg(argi, argc, argv); + } + + return -1; + } + } + } + else + { + if (nextArg) + { + // + // Try to parse the option as a remote host:port + // specification as in 'localhost:8'. Such a + // parameter can be specified at the end of the + // command line at the connecting side. + // + + char cHost[DEFAULT_STRING_LENGTH] = { '\0' }; + long cPort = 0; + + if (ParseHostOption(nextArg, cHost, cPort) > 0) + { + // + // Assume port is at a proxied display offset. + // + + proxyPort = cPort; + + cPort += DEFAULT_NX_PROXY_PORT_OFFSET; + connectSocket.setSpec(cHost, cPort); + + } + else if (ParseEnvironmentOptions(nextArg, 1) < 0) + { + return -1; + } + } + } + } + + return 1; +} + +// +// Set the variable to the values of host and +// port where this proxy is going to hook to +// an existing proxy. +// + +int ParseBindOptions(char **host, int *port) +{ + if (*bindHost != '\0') + { + *host = bindHost; + *port = bindPort; + + return 1; + } + else + { + return 0; + } +} + +// +// Read options from file and merge with environment. +// + +int ParseFileOptions(const char *file) +{ + char *fileName; + + if (*file != '/' && *file != '.') + { + char *filePath = GetSessionPath(); + + if (filePath == NULL) + { + cerr << "Error" << ": Cannot determine directory for NX option file.\n"; + + HandleCleanup(); + } + + fileName = new char[strlen(filePath) + strlen("/") + + strlen(file) + 1]; + + strcpy(fileName, filePath); + + strcat(fileName, "/"); + strcat(fileName, file); + + delete [] filePath; + } + else + { + fileName = new char[strlen(file) + 1]; + + strcpy(fileName, file); + } + + #ifdef TEST + *logofs << "Loop: Going to read options from file '" + << fileName << "'.\n" << logofs_flush; + #endif + + FILE *filePtr = fopen(fileName, "r"); + + if (filePtr == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't open options file '" << fileName + << "'. Error is " << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't open options file '" << fileName + << "'. Error is " << EGET() << " '" << ESTR() << "'.\n"; + + delete [] fileName; + + return -1; + } + + char options[DEFAULT_DISPLAY_OPTIONS_LENGTH]; + + #ifdef VALGRIND + + memset(options, '\0', DEFAULT_DISPLAY_OPTIONS_LENGTH); + + #endif + + if (fgets(options, DEFAULT_DISPLAY_OPTIONS_LENGTH, filePtr) == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't read options from file '" << fileName + << "'. Error is " << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't read options from file '" << fileName + << "'. Error is " << EGET() << " '" << ESTR() << "'.\n"; + + fclose(filePtr); + + delete [] fileName; + + return -1; + } + + fclose(filePtr); + + // + // Purge the newline and the other non- + // printable characters in the string. + // + + char *next = options; + + while (*next != '\0') + { + if (isprint(*next) == 0) + { + *next = '\0'; + } + + next++; + } + + #ifdef TEST + *logofs << "Loop: Read options '" << options << "' from file '" + << fileName << "'.\n" << logofs_flush; + #endif + + if (ParseEnvironmentOptions(options, 1) < 0) + { + delete [] fileName; + + return -1; + } + + delete [] fileName; + + return 1; +} + +// +// Parse the option string passed from the +// remote proxy at startup. +// + +int ParseRemoteOptions(char *opts) +{ + #ifdef TEST + *logofs << "Loop: Going to parse the remote options " + << "string '" << opts << "'.\n" + << logofs_flush; + #endif + + char *name; + char *value; + + // + // The options string is intended to be a series + // of name/value tuples in the form name=value + // separated by the ',' character. + // + + int hasCookie = 0; + int hasLink = 0; + int hasPack = 0; + int hasCache = 0; + int hasImages = 0; + int hasDelta = 0; + int hasStream = 0; + int hasData = 0; + int hasType = 0; + + // + // Get rid of the terminating space. + // + + if (*(opts + strlen(opts) - 1) == ' ') + { + *(opts + strlen(opts) - 1) = '\0'; + } + + name = strtok(opts, "="); + + while (name) + { + value = strtok(NULL, ","); + + if (CheckArg("remote", name, value) < 0) + { + return -1; + } + + if (strcasecmp(name, "cookie") == 0) + { + if (WE_PROVIDE_CREDENTIALS) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Ignoring remote option 'cookie' " + << "with value '" << value << "' when initiating " + << "connection.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Ignoring remote option 'cookie' " + << "with value '" << value << "' when initiating " + << "connection.\n"; + } + else if (strncasecmp(authCookie, value, strlen(authCookie)) != 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Authentication cookie '" << value + << "' doesn't match '" << authCookie << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Authentication cookie '" << value + << "' doesn't match '" << authCookie << "'.\n"; + + return -1; + } + + hasCookie = 1; + } + else if (strcasecmp(name, "link") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + if (*linkSpeedName != '\0' && strcasecmp(linkSpeedName, value) != 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Overriding option 'link' " + << "with new value '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Overriding option 'link' " + << "with new value '" << value << "'.\n"; + } + + if (ParseLinkOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify remote 'link' " + << "option in string '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify remote 'link' " + << "option in string '" << value << "'.\n"; + + return -1; + } + } + + hasLink = 1; + } + else if (strcasecmp(name, "pack") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + if (*packMethodName != '\0' && strcasecmp(packMethodName, value) != 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Overriding option 'pack' " + << "with remote value '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Overriding option 'pack' " + << "with remote value '" << value << "'.\n"; + } + + if (ParsePackOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid pack option '" + << value << "' requested by remote.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Invalid pack option '" + << value << "' requested by remote.\n"; + + return -1; + } + } + + hasPack = 1; + } + else if (strcasecmp(name, "cache") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + // + // Cache size is sent as a hint of how much memory + // the remote proxy is going to consume. A very low + // powered thin client could choose to refuse the + // connection. + // + + if (ParseCacheOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify remote 'cache' " + << "option in string '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify remote 'cache' " + << "option in string '" << value << "'.\n"; + + return -1; + } + } + + hasCache = 1; + } + else if (strcasecmp(name, "images") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + // + // Images cache size is sent as a hint. + // There is no obbligation for the local + // proxy to use the persistent cache. + // + + if (ParseImagesOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify remote 'images' " + << "option in string '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify remote 'images' " + << "option in string '" << value << "'.\n"; + + return -1; + } + } + + hasImages = 1; + } + else if (strcasecmp(name, "limit") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + if (*bitrateLimitName != '\0' && + strcasecmp(bitrateLimitName, value) != 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Overriding option 'limit' " + << "with new value '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Overriding option 'limit' " + << "with new value '" << value << "'.\n"; + } + + if (ParseBitrateOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify 'limit' " + << "option in string '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify 'limit' " + << "option in string '" << value << "'.\n"; + + return -1; + } + } + + } + else if (strcasecmp(name, "render") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + useRender = ValidateArg("remote", name, value); + } + + } + else if (strcasecmp(name, "taint") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + useTaint = ValidateArg("remote", name, value); + } + + } + else if (strcasecmp(name, "type") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + if (strcasecmp(value, "default") == 0) + { + *sessionType = '\0'; + } + else + { + strncpy(sessionType, value, DEFAULT_STRING_LENGTH - 1); + } + } + + hasType = 1; + } + else if (strcasecmp(name, "strict") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + useStrict = ValidateArg("remote", name, value); + } + + } + else if (strcasecmp(name, "shseg") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else if (ParseShmemOption(value) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't identify size of shared memory " + << "segment in string '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify size of shared memory " + << "segment in string '" << value << "'.\n"; + + return -1; + } + + } + else if (strcasecmp(name, "delta") == 0) + { + if (control -> ProxyMode == proxy_client) + { + PrintOptionIgnored("remote", name, value); + } + else + { + control -> RemoteDeltaCompression = ValidateArg("remote", name, value); + + // + // Follow for delta compression the + // same settings as the client proxy. + // + + control -> LocalDeltaCompression = control -> RemoteDeltaCompression; + } + + hasDelta = 1; + } + else if (strcasecmp(name, "stream") == 0) + { + // + // If remote side didn't choose its own + // stream compression level then assume + // local settings. + // + + if (strcasecmp(value, "default") == 0) + { + // + // This applies only at client side. + // + + control -> RemoteStreamCompression = + control -> LocalStreamCompression; + + control -> RemoteStreamCompressionLevel = + control -> LocalStreamCompressionLevel; + } + else + { + control -> RemoteStreamCompressionLevel = ValidateArg("remote", name, value); + + if (control -> RemoteStreamCompressionLevel > 0) + { + control -> RemoteStreamCompression = 1; + } + else + { + control -> RemoteStreamCompression = 0; + } + + if (control -> LocalStreamCompressionLevel < 0) + { + control -> LocalStreamCompressionLevel = ValidateArg("remote", name, value); + + if (control -> LocalStreamCompressionLevel > 0) + { + control -> LocalStreamCompression = 1; + } + else + { + control -> LocalStreamCompression = 0; + } + } + } + + hasStream = 1; + } + else if (strcasecmp(name, "data") == 0) + { + // + // Apply the same to data compression level. + // + + if (strcasecmp(value, "default") == 0) + { + control -> RemoteDataCompression = + control -> LocalDataCompression; + + control -> RemoteDataCompressionLevel = + control -> LocalDataCompressionLevel; + } + else + { + control -> RemoteDataCompressionLevel = ValidateArg("remote", name, value); + + if (control -> RemoteDataCompressionLevel > 0) + { + control -> RemoteDataCompression = 1; + } + else + { + control -> RemoteDataCompression = 0; + } + + if (control -> LocalDataCompressionLevel < 0) + { + control -> LocalDataCompressionLevel = ValidateArg("remote", name, value); + + if (control -> LocalDataCompressionLevel > 0) + { + control -> LocalDataCompression = 1; + } + else + { + control -> LocalDataCompression = 0; + } + } + } + + hasData = 1; + } + else if (strcasecmp(name, "flush") == 0) + { + // + // This option has no effect in recent + // versions. + // + + #ifdef DEBUG + *logofs << "Loop: Ignoring obsolete remote option '" + << name << "' with value '" << value + << "'.\n" << logofs_flush; + #endif + } + else + { + #ifdef WARNING + *logofs << "Loop: WARNING! Ignoring unknown remote option '" + << name << "' with value '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Ignoring unknown remote option '" + << name << "' with value '" << value << "'.\n"; + } + + name = strtok(NULL, "="); + + } // End of while (name) ... + + // + // If we are client side, we need remote 'stream' + // and 'data' options. If we are server, we need + // all the above plus 'link' and some others. + // + + char missing[DEFAULT_STRING_LENGTH]; + + *missing = '\0'; + + if (control -> ProxyMode == proxy_client) + { + if (hasStream == 0) + { + strcpy(missing, "stream"); + } + else if (hasData == 0) + { + strcpy(missing, "data"); + } + } + else + { + // + // Don't complain if the optional 'flush', + // 'render' and 'taint' options are not + // provided. + // + + if (hasLink == 0) + { + strcpy(missing, "link"); + } + else if (hasCache == 0) + { + strcpy(missing, "cache"); + } + else if (hasPack == 0) + { + strcpy(missing, "pack"); + } + else if (hasDelta == 0) + { + strcpy(missing, "delta"); + } + else if (hasStream == 0) + { + strcpy(missing, "stream"); + } + else if (hasData == 0) + { + strcpy(missing, "data"); + } + else if (hasType == 0) + { + strcpy(missing, "type"); + } + else if (hasImages == 0) + { + strcpy(missing, "images"); + } + } + + if (WE_PROVIDE_CREDENTIALS == 0) + { + // + // Can be that user doesn't have requested to + // check the authorization cookie provided by + // the connecting peer. + // + + if (hasCookie == 0 && *authCookie != '\0') + { + strcpy(missing, "cookie"); + } + } + + if (*missing != '\0') + { + #ifdef PANIC + *logofs << "Loop: PANIC! The remote peer didn't specify the option '" + << missing << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": The remote peer didn't specify the option '" + << missing << "'.\n"; + + return -1; + } + + return 1; +} + +// +// Parse the cookie provided by the NX proxy +// connection forwarder. +// + +int ParseForwarderOptions(char *opts) +{ + #ifdef TEST + *logofs << "Loop: Going to parse the forwarder options " + << "string '" << opts << "'.\n" + << logofs_flush; + #endif + + char *name; + char *value; + + int hasCookie = 0; + + // + // Get rid of the terminating space. + // + + if (*(opts + strlen(opts) - 1) == ' ') + { + *(opts + strlen(opts) - 1) = '\0'; + } + + name = strtok(opts, "="); + + while (name) + { + value = strtok(NULL, ","); + + if (CheckArg("forwarder", name, value) < 0) + { + return -1; + } + + if (strcasecmp(name, "cookie") == 0) + { + if (strncasecmp(authCookie, value, strlen(authCookie)) != 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! The NX forwarder cookie '" << value + << "' doesn't match '" << authCookie << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": The NX forwarder cookie '" << value + << "' doesn't match '" << authCookie << "'.\n"; + + return -1; + } + + hasCookie = 1; + } + else + { + #ifdef WARNING + *logofs << "Loop: WARNING! Ignoring unknown forwarder option '" + << name << "' with value '" << value << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Ignoring unknown forwarder option '" + << name << "' with value '" << value << "'.\n"; + } + + name = strtok(NULL, "="); + + } // End of while (name) ... + + if (hasCookie == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! The NX forwarder didn't provide " + << "the authentication cookie.\n" << logofs_flush; + #endif + + cerr << "Error" << ": The NX forwarder didn't provide " + << "the authentication cookie.\n"; + + return -1; + } + + return 1; +} + +int SetCore() +{ + #ifdef COREDUMPS + + rlimit rlim; + + if (getrlimit(RLIMIT_CORE, &rlim)) + { + #ifdef TEST + *logofs << "Loop: Cannot read RLIMIT_CORE. Error is '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + return -1; + } + + if (rlim.rlim_cur < rlim.rlim_max) + { + rlim.rlim_cur = rlim.rlim_max; + + if (setrlimit(RLIMIT_CORE, &rlim)) + { + #ifdef TEST + *logofs << "Loop: Cannot set RLIMIT_CORE. Error is '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + return -2; + } + } + + #ifdef TEST + *logofs << "Loop: RLIMIT_CORE is "<< rlim.rlim_max + << ".\n" << logofs_flush; + #endif + + #endif // #ifdef COREDUMPS + + return 1; +} + +char *GetLastCache(char *listBuffer, const char *searchPath) +{ + if (listBuffer == NULL || searchPath == NULL || + strncmp(listBuffer, "cachelist=", strlen("cachelist=")) != 0) + { + #ifdef TEST + *logofs << "Loop: Invalid parameters '" << listBuffer << "' and '" + << (searchPath != NULL ? searchPath : "") + << "'. Can't select any cache.\n" << logofs_flush; + #endif + + return NULL; + } + + char *selectedName = new char[MD5_LENGTH * 2 + 3]; + + *selectedName = '\0'; + + const char *localPrefix; + const char *remotePrefix; + + if (control -> ProxyMode == proxy_client) + { + localPrefix = "C-"; + remotePrefix = "S-"; + } + else + { + localPrefix = "S-"; + remotePrefix = "C-"; + } + + // + // Get rid of prefix. + // + + listBuffer += strlen("cachelist="); + + char *fileName; + + fileName = strtok(listBuffer, ","); + + // + // It is "/path/to/file" + "/" + "C-" + 32 + "\0". + // + + char fullPath[strlen(searchPath) + MD5_LENGTH * 2 + 4]; + + time_t selectedTime = 0; + + struct stat fileStat; + + while (fileName) + { + if (strncmp(fileName, "none", strlen("none")) == 0) + { + #ifdef TEST + *logofs << "Loop: No cache files seem to be available.\n" + << logofs_flush; + #endif + + delete [] selectedName; + + return NULL; + } + else if (strlen(fileName) != MD5_LENGTH * 2 + 2 || + strncmp(fileName, remotePrefix, 2) != 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Bad cache file name '" + << fileName << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Bad cache file name '" + << fileName << "'.\n"; + + delete [] selectedName; + + HandleCleanup(); + } + + #ifdef TEST + *logofs << "Loop: Parsing remote cache name '" + << fileName << "'.\n" << logofs_flush; + #endif + + // + // Prefix, received as "S-", becomes + // "C-" and viceversa. + // + + *fileName = *localPrefix; + + strcpy(fullPath, searchPath); + strcat(fullPath, "/"); + strcat(fullPath, fileName); + + if (stat(fullPath, &fileStat) == 0) + { + #ifdef TEST + *logofs << "Loop: Found a matching cache '" + << fullPath << "'.\n" << logofs_flush; + #endif + + if (fileStat.st_mtime >= selectedTime) + { + strcpy(selectedName, fileName); + + selectedTime = fileStat.st_mtime; + } + } + #ifdef TEST + else + { + *logofs << "Loop: Can't get stats of file '" + << fullPath << "'.\n" << logofs_flush; + } + #endif + + fileName = strtok(NULL, ","); + } + + if (*selectedName != '\0') + { + return selectedName; + } + else + { + delete [] selectedName; + + return NULL; + } +} + +char *GetTempPath() +{ + if (*tempDir == '\0') + { + // + // Check the NX_TEMP environment, first, + // then the TEMP variable. + // + + const char *tempEnv = getenv("NX_TEMP"); + + if (tempEnv == NULL || *tempEnv == '\0') + { + #ifdef TEST + *logofs << "Loop: WARNING! No environment for NX_TEMP.\n" + << logofs_flush; + #endif + + tempEnv = getenv("TEMP"); + + if (tempEnv == NULL || *tempEnv == '\0') + { + #ifdef TEST + *logofs << "Loop: WARNING! No environment for TEMP.\n" + << logofs_flush; + #endif + + tempEnv = "/tmp"; + } + } + + if (strlen(tempEnv) > DEFAULT_STRING_LENGTH - 1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value for the NX " + << "temporary directory '" << tempEnv + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value for the NX " + << "temporary directory '" << tempEnv + << "'.\n"; + + HandleCleanup(); + } + + strcpy(tempDir, tempEnv); + + #ifdef TEST + *logofs << "Loop: Assuming temporary NX directory '" + << tempDir << "'.\n" << logofs_flush; + #endif + } + + char *tempPath = new char[strlen(tempDir) + 1]; + + if (tempPath == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't allocate memory " + << "for the temp path.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory " + << "for the temp path.\n"; + + HandleCleanup(); + } + + strcpy(tempPath, tempDir); + + return tempPath; +} + +char *GetClientPath() +{ + if (*clientDir == '\0') + { + // + // Check the NX_CLIENT environment. + // + + const char *clientEnv = getenv("NX_CLIENT"); + + if (clientEnv == NULL || *clientEnv == '\0') + { + #ifdef TEST + *logofs << "Loop: WARNING! No environment for NX_CLIENT.\n" + << logofs_flush; + #endif + + // + // Try to guess the location of the client. + // + + clientEnv = "/usr/NX/bin/nxclient"; + + #ifdef __APPLE__ + + clientEnv = "/Applications/NX Client for OSX.app/Contents/MacOS/nxclient"; + + #endif + + #ifdef __CYGWIN32__ + + clientEnv = "C:\\Program Files\\NX Client for Windows\\nxclient"; + + #endif + } + + if (strlen(clientEnv) > DEFAULT_STRING_LENGTH - 1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value for the NX " + << "client directory '" << clientEnv + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value for the NX " + << "client directory '" << clientEnv + << "'.\n"; + + HandleCleanup(); + } + + strcpy(clientDir, clientEnv); + + #ifdef TEST + *logofs << "Loop: Assuming NX client location '" + << clientDir << "'.\n" << logofs_flush; + #endif + } + + char *clientPath = new char[strlen(clientDir) + 1]; + + if (clientPath == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't allocate memory " + << "for the client path.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory " + << "for the client path.\n"; + + HandleCleanup(); + } + + strcpy(clientPath, clientDir); + + return clientPath; +} + +char *GetSystemPath() +{ + if (*systemDir == '\0') + { + // + // Check the NX_SYSTEM environment. + // + + const char *systemEnv = getenv("NX_SYSTEM"); + + if (systemEnv == NULL || *systemEnv == '\0') + { + #ifdef TEST + *logofs << "Loop: WARNING! No environment for NX_SYSTEM.\n" + << logofs_flush; + #endif + + systemEnv = "/usr/NX"; + } + + if (strlen(systemEnv) > DEFAULT_STRING_LENGTH - 1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value for the NX " + << "system directory '" << systemEnv + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value for the NX " + << "system directory '" << systemEnv + << "'.\n"; + + HandleCleanup(); + } + + strcpy(systemDir, systemEnv); + + #ifdef TEST + *logofs << "Loop: Assuming system NX directory '" + << systemDir << "'.\n" << logofs_flush; + #endif + } + + char *systemPath = new char[strlen(systemDir) + 1]; + + if (systemPath == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't allocate memory " + << "for the system path.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory " + << "for the system path.\n"; + + HandleCleanup(); + } + + strcpy(systemPath, systemDir); + + return systemPath; +} + +char *GetHomePath() +{ + if (*homeDir == '\0') + { + // + // Check the NX_HOME environment. + // + + const char *homeEnv = getenv("NX_HOME"); + + if (homeEnv == NULL || *homeEnv == '\0') + { + #ifdef TEST + *logofs << "Loop: WARNING! No environment for NX_HOME.\n" + << logofs_flush; + #endif + + homeEnv = getenv("HOME"); + + if (homeEnv == NULL || *homeEnv == '\0') + { + #ifdef PANIC + *logofs << "Loop: PANIC! No environment for HOME.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": No environment for HOME.\n"; + + HandleCleanup(); + } + } + + if (strlen(homeEnv) > DEFAULT_STRING_LENGTH - 1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value for the NX " + << "home directory '" << homeEnv + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value for the NX " + << "home directory '" << homeEnv + << "'.\n"; + + HandleCleanup(); + } + + strcpy(homeDir, homeEnv); + + #ifdef TEST + *logofs << "Loop: Assuming NX user's home directory '" + << homeDir << "'.\n" << logofs_flush; + #endif + } + + char *homePath = new char[strlen(homeDir) + 1]; + + if (homePath == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't allocate memory " + << "for the home path.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory " + << "for the home path.\n"; + + HandleCleanup(); + } + + strcpy(homePath, homeDir); + + return homePath; +} + +char *GetRootPath() +{ + if (*rootDir == '\0') + { + // + // Check the NX_ROOT environment. + // + + const char *rootEnv = getenv("NX_ROOT"); + + if (rootEnv == NULL || *rootEnv == '\0') + { + #ifdef TEST + *logofs << "Loop: WARNING! No environment for NX_ROOT.\n" + << logofs_flush; + #endif + + // + // We will determine the root NX directory + // based on the NX_HOME or HOME directory + // settings. + // + + const char *homeEnv = GetHomePath(); + + if (strlen(homeEnv) > DEFAULT_STRING_LENGTH - + strlen("/.nx") - 1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value for the NX " + << "home directory '" << homeEnv + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value for the NX " + << "home directory '" << homeEnv + << "'.\n"; + + HandleCleanup(); + } + + #ifdef TEST + *logofs << "Loop: Assuming NX root directory in " + << "the user's home '" << homeEnv + << "'.\n" << logofs_flush; + #endif + + strcpy(rootDir, homeEnv); + strcat(rootDir, "/.nx"); + + delete [] homeEnv; + + // + // Create the NX root directory. + // + + struct stat dirStat; + + if ((stat(rootDir, &dirStat) == -1) && (EGET() == ENOENT)) + { + if (mkdir(rootDir, 0700) < 0 && (EGET() != EEXIST)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't create directory '" + << rootDir << ". Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't create directory '" + << rootDir << ". Error is " << EGET() << " '" + << ESTR() << "'.\n"; + + HandleCleanup(); + } + } + } + else + { + if (strlen(rootEnv) > DEFAULT_STRING_LENGTH - 1) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value for the NX " + << "root directory '" << rootEnv + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value for the NX " + << "root directory '" << rootEnv + << "'.\n"; + + HandleCleanup(); + } + + strcpy(rootDir, rootEnv); + } + + #ifdef TEST + *logofs << "Loop: Assuming NX root directory '" + << rootDir << "'.\n" << logofs_flush; + #endif + } + + char *rootPath = new char[strlen(rootDir) + 1]; + + if (rootPath == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't allocate memory " + << "for the root path.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory " + << "for the root path.\n"; + + HandleCleanup(); + } + + strcpy(rootPath, rootDir); + + return rootPath; +} + +char *GetCachePath() +{ + char *rootPath = GetRootPath(); + + char *cachePath; + + if (*sessionType != '\0') + { + cachePath = new char[strlen(rootPath) + strlen("/cache-") + + strlen(sessionType) + 1]; + } + else + { + cachePath = new char[strlen(rootPath) + strlen("/cache") + 1]; + } + + strcpy(cachePath, rootPath); + + if (*sessionType != '\0') + { + strcat(cachePath, "/cache-"); + + strcat(cachePath, sessionType); + } + else + { + strcat(cachePath, "/cache"); + } + + // + // Create the cache directory if needed. + // + + struct stat dirStat; + + if ((stat(cachePath, &dirStat) == -1) && (EGET() == ENOENT)) + { + if (mkdir(cachePath, 0700) < 0 && (EGET() != EEXIST)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't create directory '" << cachePath + << ". Error is " << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't create directory '" << cachePath + << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; + + delete [] rootPath; + delete [] cachePath; + + return NULL; + } + } + + delete [] rootPath; + + return cachePath; +} + +char *GetImagesPath() +{ + char *rootPath = GetRootPath(); + + char *imagesPath = new char[strlen(rootPath) + strlen("/images") + 1]; + + strcpy(imagesPath, rootPath); + + strcat(imagesPath, "/images"); + + // + // Create the cache directory if needed. + // + + struct stat dirStat; + + if ((stat(imagesPath, &dirStat) == -1) && (EGET() == ENOENT)) + { + if (mkdir(imagesPath, 0700) < 0 && (EGET() != EEXIST)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't create directory '" << imagesPath + << ". Error is " << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't create directory '" << imagesPath + << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; + + delete [] rootPath; + delete [] imagesPath; + + return NULL; + } + } + + // + // Create 16 directories in the path to + // hold the images whose name begins with + // the corresponding hexadecimal digit. + // + + char *digitPath = new char[strlen(imagesPath) + 5]; + + strcpy(digitPath, imagesPath); + + // + // Image paths have format "[path][/I-c][\0]", + // where c is the first digit of the checksum. + // + + for (char digit = 0; digit < 16; digit++) + { + sprintf(digitPath + strlen(imagesPath), "/I-%01X", digit); + + if ((stat(digitPath, &dirStat) == -1) && (EGET() == ENOENT)) + { + if (mkdir(digitPath, 0700) < 0 && (EGET() != EEXIST)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't create directory '" << digitPath + << ". Error is " << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't create directory '" << digitPath + << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; + + delete [] rootPath; + delete [] imagesPath; + delete [] digitPath; + + return NULL; + } + } + } + + delete [] rootPath; + delete [] digitPath; + + return imagesPath; +} + +char *GetSessionPath() +{ + if (*sessionDir == '\0') + { + char *rootPath = GetRootPath(); + + strcpy(sessionDir, rootPath); + + if (control -> ProxyMode == proxy_client) + { + strcat(sessionDir, "/C-"); + } + else + { + strcat(sessionDir, "/S-"); + } + + if (*sessionId == '\0') + { + char port[DEFAULT_STRING_LENGTH]; + + sprintf(port, "%d", proxyPort); + + strcpy(sessionId, port); + } + + strcat(sessionDir, sessionId); + + struct stat dirStat; + + if ((stat(sessionDir, &dirStat) == -1) && (EGET() == ENOENT)) + { + if (mkdir(sessionDir, 0700) < 0 && (EGET() != EEXIST)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't create directory '" << sessionDir + << ". Error is " << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't create directory '" << sessionDir + << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; + + delete [] rootPath; + + return NULL; + } + } + + #ifdef TEST + *logofs << "Loop: Root of NX session is '" << sessionDir + << "'.\n" << logofs_flush; + #endif + + delete [] rootPath; + } + + char *sessionPath = new char[strlen(sessionDir) + 1]; + + strcpy(sessionPath, sessionDir); + + return sessionPath; +} + +// +// Identify requested link characteristics +// and set control parameters accordingly. +// + +int ParseLinkOption(const char *opt) +{ + // + // Normalize the user input. + // + + if (strcasecmp(opt, "modem") == 0 || + strcasecmp(opt, "33k") == 0 || + strcasecmp(opt, "56k") == 0) + { + strcpy(linkSpeedName, "MODEM"); + } + else if (strcasecmp(opt, "isdn") == 0 || + strcasecmp(opt, "64k") == 0 || + strcasecmp(opt, "128k") == 0) + { + strcpy(linkSpeedName, "ISDN"); + } + else if (strcasecmp(opt, "adsl") == 0 || + strcasecmp(opt, "256k") == 0 || + strcasecmp(opt, "640k") == 0) + { + strcpy(linkSpeedName, "ADSL"); + } + else if (strcasecmp(opt, "wan") == 0 || + strcasecmp(opt, "1m") == 0 || + strcasecmp(opt, "2m") == 0 || + strcasecmp(opt, "34m") == 0) + { + strcpy(linkSpeedName, "WAN"); + } + else if (strcasecmp(opt, "lan") == 0 || + strcasecmp(opt, "10m") == 0 || + strcasecmp(opt, "100m") == 0 || + strcasecmp(opt, "local") == 0) + { + strcpy(linkSpeedName, "LAN"); + } + + if (strcasecmp(linkSpeedName, "modem") != 0 && + strcasecmp(linkSpeedName, "isdn") != 0 && + strcasecmp(linkSpeedName, "adsl") != 0 && + strcasecmp(linkSpeedName, "wan") != 0 && + strcasecmp(linkSpeedName, "lan") != 0) + { + return -1; + } + + return 1; +} + +int ParsePackOption(const char *opt) +{ + #ifdef DEBUG + *logofs << "Loop: Pack method is " << packMethod + << " quality is " << packQuality << ".\n" + << logofs_flush; + #endif + + #ifdef DEBUG + *logofs << "Loop: Parsing pack method '" << opt + << "'.\n" << logofs_flush; + #endif + + if (strcasecmp(opt, "0") == 0 || + strcasecmp(opt, "none") == 0 || + strcasecmp(opt, "nopack") == 0 || + strcasecmp(opt, "no-pack") == 0) + { + packMethod = PACK_NONE; + } + else if (strcasecmp(opt, "8") == 0) + { + packMethod = PACK_MASKED_8_COLORS; + } + else if (strcasecmp(opt, "64") == 0) + { + packMethod = PACK_MASKED_64_COLORS; + } + else if (strcasecmp(opt, "256") == 0) + { + packMethod = PACK_MASKED_256_COLORS; + } + else if (strcasecmp(opt, "512") == 0) + { + packMethod = PACK_MASKED_512_COLORS; + } + else if (strcasecmp(opt, "4k") == 0) + { + packMethod = PACK_MASKED_4K_COLORS; + } + else if (strcasecmp(opt, "32k") == 0) + { + packMethod = PACK_MASKED_32K_COLORS; + } + else if (strcasecmp(opt, "64k") == 0) + { + packMethod = PACK_MASKED_64K_COLORS; + } + else if (strcasecmp(opt, "256k") == 0) + { + packMethod = PACK_MASKED_256K_COLORS; + } + else if (strcasecmp(opt, "2m") == 0) + { + packMethod = PACK_MASKED_2M_COLORS; + } + else if (strcasecmp(opt, "16m") == 0) + { + packMethod = PACK_MASKED_16M_COLORS; + } + else if (strncasecmp(opt, "8-jpeg", strlen("8-jpeg")) == 0) + { + packMethod = PACK_JPEG_8_COLORS; + } + else if (strncasecmp(opt, "64-jpeg", strlen("64-jpeg")) == 0) + { + packMethod = PACK_JPEG_64_COLORS; + } + else if (strncasecmp(opt, "256-jpeg", strlen("256-jpeg")) == 0) + { + packMethod = PACK_JPEG_256_COLORS; + } + else if (strncasecmp(opt, "512-jpeg", strlen("512-jpeg")) == 0) + { + packMethod = PACK_JPEG_512_COLORS; + } + else if (strncasecmp(opt, "4k-jpeg", strlen("4k-jpeg")) == 0) + { + packMethod = PACK_JPEG_4K_COLORS; + } + else if (strncasecmp(opt, "32k-jpeg", strlen("32k-jpeg")) == 0) + { + packMethod = PACK_JPEG_32K_COLORS; + } + else if (strncasecmp(opt, "64k-jpeg", strlen("64k-jpeg")) == 0) + { + packMethod = PACK_JPEG_64K_COLORS; + } + else if (strncasecmp(opt, "256k-jpeg", strlen("256k-jpeg")) == 0) + { + packMethod = PACK_JPEG_256K_COLORS; + } + else if (strncasecmp(opt, "2m-jpeg", strlen("2m-jpeg")) == 0) + { + packMethod = PACK_JPEG_2M_COLORS; + } + else if (strncasecmp(opt, "16m-jpeg", strlen("16m-jpeg")) == 0) + { + packMethod = PACK_JPEG_16M_COLORS; + } + else if (strncasecmp(opt, "8-png", strlen("8-png")) == 0) + { + packMethod = PACK_PNG_8_COLORS; + } + else if (strncasecmp(opt, "64-png", strlen("64-png")) == 0) + { + packMethod = PACK_PNG_64_COLORS; + } + else if (strncasecmp(opt, "256-png", strlen("256-png")) == 0) + { + packMethod = PACK_PNG_256_COLORS; + } + else if (strncasecmp(opt, "512-png", strlen("512-png")) == 0) + { + packMethod = PACK_PNG_512_COLORS; + } + else if (strncasecmp(opt, "4k-png", strlen("4k-png")) == 0) + { + packMethod = PACK_PNG_4K_COLORS; + } + else if (strncasecmp(opt, "32k-png", strlen("32k-png")) == 0) + { + packMethod = PACK_PNG_32K_COLORS; + } + else if (strncasecmp(opt, "64k-png", strlen("64k-png")) == 0) + { + packMethod = PACK_PNG_64K_COLORS; + } + else if (strncasecmp(opt, "256k-png", strlen("256k-png")) == 0) + { + packMethod = PACK_PNG_256K_COLORS; + } + else if (strncasecmp(opt, "2m-png", strlen("2m-png")) == 0) + { + packMethod = PACK_PNG_2M_COLORS; + } + else if (strncasecmp(opt, "16m-png", strlen("16m-png")) == 0) + { + packMethod = PACK_PNG_16M_COLORS; + } + else if (strncasecmp(opt, "16m-rgb", strlen("16m-rgb")) == 0 || + strncasecmp(opt, "rgb", strlen("rgb")) == 0) + { + packMethod = PACK_RGB_16M_COLORS; + } + else if (strncasecmp(opt, "16m-rle", strlen("16m-rle")) == 0 || + strncasecmp(opt, "rle", strlen("rle")) == 0) + { + packMethod = PACK_RLE_16M_COLORS; + } + else if (strncasecmp(opt, "16m-bitmap", strlen("16m-bitmap")) == 0 || + strncasecmp(opt, "bitmap", strlen("bitmap")) == 0) + { + packMethod = PACK_BITMAP_16M_COLORS; + } + else if (strncasecmp(opt, "lossy", strlen("lossy")) == 0) + { + packMethod = PACK_LOSSY; + } + else if (strncasecmp(opt, "lossless", strlen("lossless")) == 0) + { + packMethod = PACK_LOSSLESS; + } + else if (strncasecmp(opt, "adaptive", strlen("adaptive")) == 0) + { + packMethod = PACK_ADAPTIVE; + } + else + { + return -1; + } + + if (packMethod == PACK_NONE) + { + strcpy(packMethodName, "none"); + } + else + { + strcpy(packMethodName, opt); + } + + if (packMethod == PACK_RGB_16M_COLORS || + packMethod == PACK_RLE_16M_COLORS || + packMethod == PACK_BITMAP_16M_COLORS || + (packMethod >= PACK_JPEG_8_COLORS && + packMethod <= PACK_JPEG_16M_COLORS) || + (packMethod >= PACK_PNG_8_COLORS && + packMethod <= PACK_PNG_16M_COLORS) || + packMethod == PACK_LOSSY || + packMethod == PACK_LOSSLESS || + packMethod == PACK_ADAPTIVE) + { + const char *dash = strrchr(opt, '-'); + + if (dash != NULL && strlen(dash) == 2 && + *(dash + 1) >= '0' && *(dash + 1) <= '9') + { + packQuality = atoi(dash + 1); + + #ifdef DEBUG + *logofs << "Loop: Using pack quality '" + << packQuality << "'.\n" << logofs_flush; + #endif + } + } + else + { + packQuality = 0; + } + + return 1; +} + +int ParsePackMethod(const int method, const int quality) +{ + switch (method) + { + case PACK_NONE: + { + strcpy(packMethodName, "none"); + + break; + } + case PACK_MASKED_8_COLORS: + { + strcpy(packMethodName, "8"); + + break; + } + case PACK_MASKED_64_COLORS: + { + strcpy(packMethodName, "64"); + + break; + } + case PACK_MASKED_256_COLORS: + { + strcpy(packMethodName, "256"); + + break; + } + case PACK_MASKED_512_COLORS: + { + strcpy(packMethodName, "512"); + + break; + } + case PACK_MASKED_4K_COLORS: + { + strcpy(packMethodName, "4k"); + + break; + } + case PACK_MASKED_32K_COLORS: + { + strcpy(packMethodName, "32k"); + + break; + } + case PACK_MASKED_64K_COLORS: + { + strcpy(packMethodName, "64k"); + + break; + } + case PACK_MASKED_256K_COLORS: + { + strcpy(packMethodName, "256k"); + + break; + } + case PACK_MASKED_2M_COLORS: + { + strcpy(packMethodName, "2m"); + + break; + } + case PACK_MASKED_16M_COLORS: + { + strcpy(packMethodName, "16m"); + + break; + } + case PACK_JPEG_8_COLORS: + { + strcpy(packMethodName, "8-jpeg"); + + break; + } + case PACK_JPEG_64_COLORS: + { + strcpy(packMethodName, "64-jpeg"); + + break; + } + case PACK_JPEG_256_COLORS: + { + strcpy(packMethodName, "256-jpeg"); + + break; + } + case PACK_JPEG_512_COLORS: + { + strcpy(packMethodName, "512-jpeg"); + + break; + } + case PACK_JPEG_4K_COLORS: + { + strcpy(packMethodName, "4k-jpeg"); + + break; + } + case PACK_JPEG_32K_COLORS: + { + strcpy(packMethodName, "32k-jpeg"); + + break; + } + case PACK_JPEG_64K_COLORS: + { + strcpy(packMethodName, "64k-jpeg"); + + break; + } + case PACK_JPEG_256K_COLORS: + { + strcpy(packMethodName, "256k-jpeg"); + + break; + } + case PACK_JPEG_2M_COLORS: + { + strcpy(packMethodName, "2m-jpeg"); + + break; + } + case PACK_JPEG_16M_COLORS: + { + strcpy(packMethodName, "16m-jpeg"); + + break; + } + case PACK_PNG_8_COLORS: + { + strcpy(packMethodName, "8-png"); + + break; + } + case PACK_PNG_64_COLORS: + { + strcpy(packMethodName, "64-png"); + + break; + } + case PACK_PNG_256_COLORS: + { + strcpy(packMethodName, "256-png"); + + break; + } + case PACK_PNG_512_COLORS: + { + strcpy(packMethodName, "512-png"); + + break; + } + case PACK_PNG_4K_COLORS: + { + strcpy(packMethodName, "4k-png"); + + break; + } + case PACK_PNG_32K_COLORS: + { + strcpy(packMethodName, "32k-png"); + + break; + } + case PACK_PNG_64K_COLORS: + { + strcpy(packMethodName, "64k-png"); + + break; + } + case PACK_PNG_256K_COLORS: + { + strcpy(packMethodName, "256k-png"); + + break; + } + case PACK_PNG_2M_COLORS: + { + strcpy(packMethodName, "2m-png"); + + break; + } + case PACK_PNG_16M_COLORS: + { + strcpy(packMethodName, "16m-png"); + + break; + } + case PACK_RGB_16M_COLORS: + { + strcpy(packMethodName, "16m-rgb"); + + break; + } + case PACK_RLE_16M_COLORS: + { + strcpy(packMethodName, "16m-rle"); + + break; + } + case PACK_BITMAP_16M_COLORS: + { + strcpy(packMethodName, "16m-bitmap"); + + break; + } + case PACK_LOSSY: + { + strcpy(packMethodName, "lossy"); + + break; + } + case PACK_LOSSLESS: + { + strcpy(packMethodName, "lossless"); + + break; + } + case PACK_ADAPTIVE: + { + strcpy(packMethodName, "adaptive"); + + break; + } + default: + { + return -1; + } + } + + if (quality < 0 || quality > 9) + { + return -1; + } + + if (packMethod == PACK_RGB_16M_COLORS || + packMethod == PACK_RLE_16M_COLORS || + packMethod == PACK_BITMAP_16M_COLORS || + (packMethod >= PACK_JPEG_8_COLORS && + packMethod <= PACK_JPEG_16M_COLORS) || + (packMethod >= PACK_PNG_8_COLORS && + packMethod <= PACK_PNG_16M_COLORS) || + packMethod == PACK_LOSSY || + packMethod == PACK_LOSSLESS || + packMethod == PACK_ADAPTIVE) + { + sprintf(packMethodName + strlen(packMethodName), + "-%d", quality); + } + + packMethod = method; + packQuality = quality; + + control -> PackMethod = packMethod; + control -> PackQuality = packQuality; + + return 1; +} + +int SetDirectories() +{ + // + // Determine the location of the user's NX + // directory and the other relevant paths. + // The functions below will check the pa- + // rameters passed to the program and will + // query the environment, if needed. + // + + control -> HomePath = GetHomePath(); + control -> RootPath = GetRootPath(); + control -> SystemPath = GetSystemPath(); + control -> TempPath = GetTempPath(); + control -> ClientPath = GetClientPath(); + + return 1; +} + +int SetLogs() +{ + // + // So far we used stderr (or stdout under + // WIN32). Now use the files selected by + // the user. + // + + if (*statsFileName == '\0') + { + strcpy(statsFileName, "stats"); + + #ifdef TEST + *logofs << "Loop: Assuming default statistics file '" + << statsFileName << "'.\n" << logofs_flush; + #endif + } + #ifdef TEST + else + { + *logofs << "Loop: Name selected for statistics is '" + << statsFileName << "'.\n" << logofs_flush; + } + #endif + + if (OpenLogFile(statsFileName, statofs) < 0) + { + HandleCleanup(); + } + + #ifndef MIXED + + if (*errorsFileName == '\0') + { + strcpy(errorsFileName, "errors"); + + #ifdef TEST + *logofs << "Loop: Assuming default log file name '" + << errorsFileName << "'.\n" << logofs_flush; + #endif + } + #ifdef TEST + else + { + *logofs << "Loop: Name selected for log file is '" + << errorsFileName << "'.\n" << logofs_flush; + } + #endif + + // + // Share the bebug output with the nxssh binder + // process. The file must be made writable by + // everybody because the nxssh process is run by + // nxserver as the nx user. + // + + #ifdef BINDER + + strcpy(errorsFileName, "/tmp/errors"); + + ostream *tmpfs = new ofstream(errorsFileName, ios::out); + + delete tmpfs; + + chmod(errorsFileName, S_IRUSR | S_IWUSR | S_IRGRP | + S_IWGRP | S_IROTH | S_IWOTH); + + #endif + + if (OpenLogFile(errorsFileName, logofs) < 0) + { + HandleCleanup(); + } + + // + // By default the session log is the standard error + // of the process. It is anyway required to set the + // option when running inside SSH, otherwise the + // output will go to the same file as the SSH log, + // depending where the NX client has redirected the + // output. + // + + if (*sessionFileName != '\0') + { + #ifdef TEST + *logofs << "Loop: Name selected for session file is '" + << sessionFileName << "'.\n" << logofs_flush; + #endif + + if (errofs != NULL) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Unexpected value for stream errofs.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Unexpected value for stream errofs.\n"; + } + + if (errsbuf != NULL) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Unexpected value for buffer errsbuf.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Unexpected value for buffer errsbuf.\n"; + } + + errofs = NULL; + errsbuf = NULL; + + if (OpenLogFile(sessionFileName, errofs) < 0) + { + HandleCleanup(); + } + + // + // Redirect the standard error to the file. + // + + errsbuf = cerr.rdbuf(errofs -> rdbuf()); + } + + #endif + + return 1; +} + +int SetPorts() +{ + // + // Depending on the proxy side, we need to determine on which + // port to listen for the given protocol or to which port we + // will have to forward the connection. Three possibilities + // are given for each supported protocol: + // + // Port <= 0: Disable port forwarding. + // Port == 1: Use the default port. + // Port > 1: Use the specified port. + // + // At the connectiong side the user should always explicitly + // set the ports where the connections will be forwarded. This + // is both for security reasons and because, when running both + // proxies on the same host, there is a concrete possibility + // that, by using the default ports, the connection will be + // forwarded to the same port where the peer proxy is listen- + // ing, causing a loop. + // + + useCupsSocket = 0; + if (cupsPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + cupsPort.setDefaultTCPPort(DEFAULT_NX_CUPS_PORT_OFFSET + proxyPort); + useCupsSocket = 1; + } + else + cupsPort.setDefaultTCPPort(631); + } + +#ifdef TEST + *logofs << "Loop: cups port: " << cupsPort << "\n" + << logofs_flush; +#endif + + useAuxSocket = 0; + if (auxPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + auxPort.setDefaultTCPPort(DEFAULT_NX_AUX_PORT_OFFSET + proxyPort); + useAuxSocket = 1; + } + else { + auxPort.setDefaultTCPPort(1); + + if (auxPort.getTCPPort() != 1) { + +#ifdef WARNING + *logofs << "Loop: WARNING! Overriding auxiliary X11 " + << "port with new value '" << 1 << "'.\n" + << logofs_flush; +#endif + + cerr << "Warning" << ": Overriding auxiliary X11 " + << "port with new value '" << 1 << "'.\n"; + + auxPort.setSpec("1"); + } + } + } + +#ifdef TEST + *logofs << "Loop: aux port: " << auxPort << "\n" + << logofs_flush; +#endif + + useSmbSocket = 0; + if (smbPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + auxPort.setDefaultTCPPort(DEFAULT_NX_SMB_PORT_OFFSET + proxyPort); + useAuxSocket = 1; + } + else + auxPort.setDefaultTCPPort(139); + } + + +#ifdef TEST + *logofs << "Loop: smb port: " << smbPort << "\n" + << logofs_flush; +#endif + + useMediaSocket = 0; + if (mediaPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + mediaPort.setDefaultTCPPort(DEFAULT_NX_MEDIA_PORT_OFFSET + proxyPort); + useMediaSocket = 1; + } + else if (mediaPort.getTCPPort() == 1) { +#ifdef PANIC + *logofs << "Loop: PANIC! No port specified for multimedia connections.\n" + << logofs_flush; +#endif + + cerr << "Error" << ": No port specified for multimedia connections.\n"; + + HandleCleanup(); + } + } + +#ifdef TEST + *logofs << "Loop: Using multimedia port '" << mediaPort + << "'.\n" << logofs_flush; +#endif + + useHttpSocket = 0; + if (httpPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + httpPort.setDefaultTCPPort(DEFAULT_NX_HTTP_PORT_OFFSET + proxyPort); + useHttpSocket = 1; + } + else + httpPort.setDefaultTCPPort(80); + } + +#ifdef TEST + *logofs << "Loop: Using HTTP port '" << httpPort + << "'.\n" << logofs_flush; +#endif + + if (ParseFontPath(fontPort) <= 0) + { + #ifdef TEST + *logofs << "Loop: Disabling font server connections.\n" + << logofs_flush; + #endif + + *fontPort = '\0'; + + useFontSocket = 0; + } + else + { + // + // We don't know yet if the remote proxy supports + // the font server connections. If needed, we will + // disable the font server connections at later + // time. + // + + if (control -> ProxyMode == proxy_server) + { + useFontSocket = 1; + } + else + { + useFontSocket = 0; + } + + #ifdef TEST + *logofs << "Loop: Using font server port '" << fontPort + << "'.\n" << logofs_flush; + #endif + } + + useSlaveSocket = 0; + if (slavePort.enabled()) { + useSlaveSocket = 1; + if (control -> ProxyMode == proxy_client) + slavePort.setDefaultTCPPort(DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET + proxyPort); + else + slavePort.setDefaultTCPPort(DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET + proxyPort); + } + +#ifdef TEST + *logofs << "Loop: Using slave port '" << slavePort + << "'.\n" << logofs_flush; +#endif + + return 1; +} + +int SetDescriptors() +{ + unsigned int limit = 0; + + #ifdef RLIMIT_NOFILE + + rlimit limits; + + if (getrlimit(RLIMIT_NOFILE, &limits) == 0) + { + if (limits.rlim_max == RLIM_INFINITY) + { + limit = 0; + } + else + { + limit = (unsigned int) limits.rlim_max; + } + } + + #endif + + #ifdef _SC_OPEN_MAX + + if (limit == 0) + { + limit = sysconf(_SC_OPEN_MAX); + } + + #endif + + #ifdef FD_SETSIZE + + if (limit > FD_SETSIZE) + { + limit = FD_SETSIZE; + } + + #endif + + #ifdef RLIMIT_NOFILE + + if (limits.rlim_cur < limit) + { + limits.rlim_cur = limit; + + setrlimit(RLIMIT_NOFILE, &limits); + } + + #endif + + if (limit == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Cannot determine number of available " + << "file descriptors.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot determine number of available " + << "file descriptors.\n"; + + return -1; + } + + return 1; +} + +// +// Find the directory containing the caches +// matching the session type. +// + +int SetCaches() +{ + if ((control -> PersistentCachePath = GetCachePath()) == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error getting or creating the cache path.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error getting or creating the cache path.\n"; + + HandleCleanup(); + } + + #ifdef TEST + *logofs << "Loop: Path of cache files is '" << control -> PersistentCachePath + << "'.\n" << logofs_flush; + #endif + + return 1; +} + +// +// Initialize all configuration parameters. +// + +int SetParameters() +{ + // + // Find out the type of session. + // + + SetSession(); + + // + // Initialize the network and compression + // parameters according to the settings + // suggested by the user. + // + + SetLink(); + + // + // Set compression according to link speed. + // + + SetCompression(); + + // + // Be sure that we have a literal for current + // cache size. Value will reflect control's + // default unless we already parsed a 'cache' + // option. Server side has no control on size + // of cache but is informed at session nego- + // tiation about how much memory is going to + // be used. + // + + SetStorage(); + + // + // Set size of shared memory segments. + // + + SetShmem(); + + // + // Make adjustments to cache based + // on the pack method. + // + + SetPack(); + + // + // Set disk-based image cache. + // + + SetImages(); + + // + // Set CPU and bandwidth limits. + // + + SetLimits(); + + return 1; +} + +// +// According to session literal determine +// the type of traffic that is going to be +// transported. Literals should be better +// standardized in future NX versions. +// + +int SetSession() +{ + if (strncmp(sessionType, "agent", strlen("agent")) == 0 || + strncmp(sessionType, "desktop", strlen("desktop")) == 0 || + strncmp(sessionType, "rootless", strlen("rootless")) == 0 || + strncmp(sessionType, "console", strlen("console")) == 0 || + strncmp(sessionType, "default", strlen("default")) == 0 || + strncmp(sessionType, "gnome", strlen("gnome")) == 0 || + strncmp(sessionType, "kde", strlen("kde")) == 0 || + strncmp(sessionType, "cde", strlen("cde")) == 0 || + strncmp(sessionType, "xdm", strlen("xdm")) == 0) + { + control -> SessionMode = session_agent; + } + else if (strncmp(sessionType, "win", strlen("win")) == 0 || + strncmp(sessionType, "vnc", strlen("vnc")) == 0) + { + control -> SessionMode = session_agent; + } + else if (strncmp(sessionType, "shadow", strlen("shadow")) == 0) + { + control -> SessionMode = session_shadow; + } + else if (strncmp(sessionType, "proxy", strlen("proxy")) == 0 || + strncmp(sessionType, "application", strlen("application")) == 0 || + strncmp(sessionType, "raw", strlen("raw")) == 0) + { + control -> SessionMode = session_proxy; + } + else + { + // + // If the session type is not passed or + // it is not among the recognized strings, + // we assume that the proxy is connected + // to the agent. + // + + // + // Since ProtoStep8 (#issue 108) and also + // with older "unix-" sessions + // + + if (*sessionType != '\0') + { + #ifdef WARNING + *logofs << "Loop: WARNING! Unrecognized session type '" + << sessionType << "'. Assuming agent session.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Unrecognized session type '" + << sessionType << "'. Assuming agent session.\n"; + } + + control -> SessionMode = session_agent; + } + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Assuming session type '" + << DumpSession(control -> SessionMode) << "' with " + << "string '" << sessionType << "'.\n" + << logofs_flush; + #endif + + // + // By default the policy is immediate. Agents + // will set a different policy, if they like. + // Anyway we need to check if the user has + // provided a custom flush policy. + // + + if (usePolicy != -1) + { + if (usePolicy > 0) + { + control -> FlushPolicy = policy_deferred; + } + else + { + control -> FlushPolicy = policy_immediate; + } + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: WARNING! Forcing flush policy to '" + << DumpPolicy(control -> FlushPolicy) + << ".\n" << logofs_flush; + #endif + } + else + { + control -> FlushPolicy = policy_immediate; + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Setting initial flush policy to '" + << DumpPolicy(control -> FlushPolicy) + << "'.\n" << logofs_flush; + #endif + } + + // + // Check if the proxy library is run inside + // another program providing encryption, as + // it is the case of the SSH client. + // + + if (useEncryption != -1) + { + if (useEncryption > 0) + { + control -> LinkEncrypted = 1; + } + else + { + control -> LinkEncrypted = 0; + } + } + + if (control -> LinkEncrypted == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Proxy running as part of an " + << "encrypting client.\n" + << logofs_flush; + #endif + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Assuming proxy running as a " + << "standalone program.\n" + << logofs_flush; + #endif + } + + // + // Check if the system administrator has + // enabled the respawn of the client at + // the end of session. + // + + if (control -> ProxyMode == proxy_server) + { + struct stat fileStat; + + char fileName[DEFAULT_STRING_LENGTH]; + + snprintf(fileName, DEFAULT_STRING_LENGTH - 1, + "%s/share/noexit", control -> SystemPath); + + *(fileName + DEFAULT_STRING_LENGTH - 1) = '\0'; + + if (stat(fileName, &fileStat) == 0) + { + #ifdef TEST + *logofs << "Loop: Enabling respawn of client at session shutdown.\n" + << logofs_flush; + #endif + + control -> EnableRestartOnShutdown = 1; + } + } + + return 1; +} + +int SetStorage() +{ + // + // If differential compression is disabled + // we don't need a cache at all. + // + + if (control -> LocalDeltaCompression == 0) + { + control -> ClientTotalStorageSize = 0; + control -> ServerTotalStorageSize = 0; + } + + // + // Set a a cache size literal. + // + + int size = control -> getUpperStorageSize(); + + if (size / 1024 > 0) + { + sprintf(cacheSizeName, "%dk", size / 1024); + } + else + { + sprintf(cacheSizeName, "%d", size); + } + + if (control -> ProxyMode == proxy_client) + { + control -> LocalTotalStorageSize = + control -> ClientTotalStorageSize; + + control -> RemoteTotalStorageSize = + control -> ServerTotalStorageSize; + } + else + { + control -> LocalTotalStorageSize = + control -> ServerTotalStorageSize; + + control -> RemoteTotalStorageSize = + control -> ClientTotalStorageSize; + } + + #ifdef DEBUG + *logofs << "Loop: Storage size limit is " + << control -> ClientTotalStorageSize + << " at client and " + << control -> ServerTotalStorageSize + << " at server.\n" + << logofs_flush; + #endif + + #ifdef DEBUG + *logofs << "Loop: Storage local limit set to " + << control -> LocalTotalStorageSize + << " remote limit set to " + << control -> RemoteTotalStorageSize + << ".\n" << logofs_flush; + #endif + + // + // Never reserve for split store more than + // half the memory available for messages. + // + + if (size > 0 && control -> + SplitTotalStorageSize > size / 2) + { + #ifdef TEST + *logofs << "Loop: Reducing size of split store to " + << size / 2 << " bytes.\n" + << logofs_flush; + #endif + + control -> SplitTotalStorageSize = size / 2; + } + + // + // Don't load render from persistent + // cache if extension is hidden or + // not supported by agent. + // + + if (control -> HideRender == 1) + { + #ifdef TEST + *logofs << "Loop: Not loading render extension " + << "from persistent cache.\n" + << logofs_flush; + #endif + + control -> PersistentCacheLoadRender = 0; + } + + return 1; +} + +int SetShmem() +{ + // + // If not set, adjust the size of the shared + // memory segment according to size of the + // message cache. + // + + if (*shsegSizeName == '\0') + { + int size = control -> getUpperStorageSize(); + + const int mega = 1048576; + + if (size > 0) + { + if (size <= 1 * mega) + { + size = 0; + } + else if (size <= 2 * mega) + { + size = 524288; + } + else if (size < 4 * mega) + { + size = 1048576; + } + else + { + size = size / 4; + } + + if (size > 4194304) + { + size = 4194304; + } + + control -> ShmemClientSize = size; + control -> ShmemServerSize = size; + } + else + { + // + // The delta compression is disabled. + // Use a default segment size of 2 MB. + // + + control -> ShmemServerSize = 2 * mega; + } + } + + // + // Client side shared memory support is + // not useful and not implemented. + // + + if (control -> ShmemServerSize >= 524288) + { + control -> ShmemServer = 1; + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Set initial shared memory size " + << "to " << control -> ShmemServerSize + << " bytes.\n" << logofs_flush; + #endif + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Disabled use of the shared memory " + << "extension.\n" << logofs_flush; + #endif + + control -> ShmemServer = 0; + } + + // For android, no shared memory available + control -> ShmemServer = 0; + control -> ShmemClientSize = 0; + + return 1; +} + +// +// Adjust the pack method according to the +// type of the session. +// + +int SetPack() +{ + #ifdef TEST + *logofs << "Loop: Setting pack with initial method " + << packMethod << " and quality " << packQuality + << ".\n" << logofs_flush; + #endif + + // + // Check if this is a proxy session and, in + // this case, set the pack method to none. + // Packed images are not supported by plain + // X applications. + // + + if (control -> SessionMode == session_proxy) + { + #ifdef TEST + *logofs << "Loop: WARNING! Disabling pack with proxy session.\n" + << logofs_flush; + #endif + + packMethod = PACK_NONE; + } + + // + // Adjust the internal settings according + // to the newly selected pack method. + // + + ParsePackMethod(packMethod, packQuality); + + // + // Don't load messages from persistent + // cache if packed images are disabled. + // + + if (control -> PackMethod == PACK_NONE) + { + control -> PersistentCacheLoadPacked = 0; + + #ifdef TEST + *logofs << "Loop: Not loading packed images " + << "from persistent cache.\n" + << logofs_flush; + #endif + } + + return 1; +} + +// +// Set the disk-based image cache parameters +// according to the user's wishes. +// + +int SetImages() +{ + // + // Be sure we disable the image cache if we + // are connecting to plain X clients. + // + + if (control -> SessionMode == session_proxy) + { + #ifdef TEST + *logofs << "Loop: Disabling image cache with " + << "session '" << DumpSession(control -> + SessionMode) << "'.\n" << logofs_flush; + #endif + + sprintf(imagesSizeName, "0"); + + control -> ImageCacheEnableLoad = 0; + control -> ImageCacheEnableSave = 0; + + return 1; + } + + int size = control -> ImageCacheDiskLimit; + + if (size / 1024 > 0) + { + sprintf(imagesSizeName, "%dk", size / 1024); + } + else + { + sprintf(imagesSizeName, "%d", size); + } + + if (size > 0) + { + control -> ImageCacheEnableLoad = 1; + control -> ImageCacheEnableSave = 1; + + if (control -> ProxyMode == proxy_server) + { + if ((control -> ImageCachePath = GetImagesPath()) == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error getting or creating image cache path.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error getting or creating image cache path.\n"; + + HandleCleanup(); + } + + #ifdef TEST + *logofs << "Loop: Path of image cache files is '" << control -> ImageCachePath + << "'.\n" << logofs_flush; + #endif + } + } + else + { + #ifdef TEST + *logofs << "Loop: Disabling the persistent image cache.\n" + << logofs_flush; + #endif + + control -> ImageCacheEnableLoad = 0; + control -> ImageCacheEnableSave = 0; + } + + return 1; +} + +int SetVersion() +{ + // + // Normalize the different proxy versions. + // + + int local = (control -> LocalVersionMajor << 24) | + (control -> LocalVersionMinor << 16) | + control -> LocalVersionPatch; + + int remote = (control -> RemoteVersionMajor << 24) | + (control -> RemoteVersionMinor << 16) | + control -> RemoteVersionPatch; + + int major = -1; + int minor = -1; + int patch = -1; + + if (control -> RemoteVersionMajor <= 1) + { + // + // The remote proxy uses a different + // logic to determine the version so + // we default to the compatibility + // version. + // + + major = control -> CompatVersionMajor; + minor = control -> CompatVersionMinor; + patch = control -> CompatVersionPatch; + + #ifdef TEST + *logofs << "Loop: Using compatibility version '" + << major << "." << minor << "." << patch + << "'.\n" << logofs_flush; + #endif + } + else if (control -> LocalVersionMajor > + control -> RemoteVersionMajor) + { + // + // We use a more recent version. Let's + // negotiate the version based on the + // version supported by the remote. + // + + major = control -> RemoteVersionMajor; + minor = control -> RemoteVersionMinor; + patch = control -> RemoteVersionPatch; + + #ifdef TEST + *logofs << "Loop: Using remote version '" + << major << "." << minor << "." << patch + << "'.\n" << logofs_flush; + #endif + } + else + { + // + // We support a major version that is + // equal or older than the remote. We + // assume the smaller version between + // the two, including the minor and + // the patch numbers. + // + + if (local > remote) + { + major = control -> RemoteVersionMajor; + minor = control -> RemoteVersionMinor; + patch = control -> RemoteVersionPatch; + + #ifdef TEST + *logofs << "Loop: Using remote version '" + << major << "." << minor << "." << patch + << "'.\n" << logofs_flush; + #endif + } + else + { + major = control -> LocalVersionMajor; + minor = control -> LocalVersionMinor; + patch = control -> LocalVersionPatch; + + #ifdef TEST + *logofs << "Loop: Using local version '" + << major << "." << minor << "." << patch + << "'.\n" << logofs_flush; + #endif + } + } + + // + // Handle versions from 3.5.0. The protocol + // step 10 is the minimum supported version. + // + + int step = 0; + + if (major == 3) + { + if (minor >= 5) + { + step = 10; + } + } + else if (major > 3) + { + step = 10; + } + + if (step == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Unable to set the protocol step value from " + << "the negotiated protocol version " << major << "." << minor + << "." << patch << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unable to set the protocol step value from " + << "the negotiated protocol version " << major << "." << minor + << "." << patch << ".\n"; + + #ifdef PANIC + *logofs << "Loop: PANIC! Incompatible remote version " + << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor + << "." << control -> RemoteVersionPatch << " with local version " + << control -> LocalVersionMajor << "." << control -> LocalVersionMinor + << "." << control -> LocalVersionPatch << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Incompatible remote version " + << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor + << "." << control -> RemoteVersionPatch << " with local version " + << control -> LocalVersionMajor << "." << control -> LocalVersionMinor + << "." << control -> LocalVersionPatch << ".\n"; + + return -1; + } + + #ifdef TEST + *logofs << "Loop: Using NX protocol step " + << step << ".\n" << logofs_flush; + #endif + + control -> setProtoStep(step); + + // + // Ignore the differences in patch version + // and print a warning if the local version + // is different or obsolete compared to + // the remote. + // + + local &= 0xffff0000; + remote &= 0xffff0000; + + if (local != remote) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Connected to remote version " + << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor + << "." << control -> RemoteVersionPatch << " with local version " + << control -> LocalVersionMajor << "." << control -> LocalVersionMinor + << "." << control -> LocalVersionPatch << ".\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Connected to remote version " + << control -> RemoteVersionMajor << "." << control -> RemoteVersionMinor + << "." << control -> RemoteVersionPatch << " with local version " + << control -> LocalVersionMajor << "." << control -> LocalVersionMinor + << "." << control -> LocalVersionPatch << ".\n" << logofs_flush; + } + + if (local < remote) + { + cerr << "Warning" << ": Consider checking https://github.com/ArcticaProject/nx-libs/releases for updates.\n"; + } + + // + // Now that we are aware of the remote + // version, let's adjust the options to + // be compatible with the remote proxy. + // + + if (control -> ProxyMode == proxy_client) + { + // + // Since ProtoStep8 (#issue 108) + // + // Now it's assumed that the remote is + // able to handle the selected pack + // method + // + + #ifdef TEST + *logofs << __FILE__ << " : " << __LINE__ << " - " + << "step = " << control -> getProtoStep() + << " packMethod = " << packMethod + << " packQuality = " << packQuality + << ".\n" << logofs_flush; + #endif + + // + // Update the pack method name. + // + + ParsePackMethod(packMethod, packQuality); + } + + // + // At the moment the image cache is not used by the + // agent. Proxy versions older than 3.0.0 assumed + // that it was enabled and sent specific bits as part + // of the encoding. Conversely, it is advisable to + // disable the cache right now. By not enabling the + // the image cache, the house-keeping process will + // only take care of cleaning up the "cache-" direc- + // tories. + // + + // + // Considering that compatibility with older versions + // has been set to cover as far as 3.5.0, the cache can + // be disabled at this point without any concern + // + + // Since ProtoStep8 (#issue 108) + #ifdef TEST + *logofs << "Loop: Disabling image cache with protocol " + << "step '" << control -> getProtoStep() + << "'.\n" << logofs_flush; + #endif + + sprintf(imagesSizeName, "0"); + + control -> ImageCacheEnableLoad = 0; + control -> ImageCacheEnableSave = 0; + + return 1; +} + +// +// Identify the requested link settings +// and update the control parameters +// accordingly. +// + +int SetLink() +{ + #ifdef TEST + *logofs << "Loop: Setting link with initial value " + << linkSpeedName << ".\n" << logofs_flush; + #endif + + if (*linkSpeedName == '\0') + { + strcpy(linkSpeedName, "lan"); + } + + #ifdef TEST + *logofs << "Loop: Link speed is " << linkSpeedName + << ".\n" << logofs_flush; + #endif + + if (strcasecmp(linkSpeedName, "modem") == 0) + { + SetLinkModem(); + } + else if (strcasecmp(linkSpeedName, "isdn") == 0) + { + SetLinkIsdn(); + } + else if (strcasecmp(linkSpeedName, "adsl") == 0) + { + SetLinkAdsl(); + } + else if (strcasecmp(linkSpeedName, "wan") == 0) + { + SetLinkWan(); + } + else if (strcasecmp(linkSpeedName, "lan") == 0) + { + SetLinkLan(); + } + else + { + return -1; + } + + // + // Set TCP_NODELAY according to the user's + // wishes. + // + + if (useNoDelay != -1) + { + control -> OptionProxyClientNoDelay = useNoDelay; + control -> OptionProxyServerNoDelay = useNoDelay; + } + + // + // Select the image compression method. + // + + if (packMethod == -1) + { + packMethod = control -> PackMethod; + } + + if (packQuality == -1) + { + packQuality = control -> PackQuality; + } + + if (ParsePackMethod(packMethod, packQuality) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Unrecognized pack method id " + << packMethod << " with quality " << packQuality + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unrecognized pack method id " + << packMethod << " with quality " << packQuality + << ".\n"; + + HandleCleanup(); + } + + // + // Check if the user disabled the ability + // to generate simple replies at the client + // side. + // + + if (control -> SessionMode == session_proxy) + { + if (useTaint != -1) + { + control -> TaintReplies = (useTaint == 1); + } + else + { + #ifdef WARNING + *logofs << "Loop: WARNING! Forcing taint of replies " + << "with a proxy session.\n" + << logofs_flush; + #endif + + control -> TaintReplies = 1; + } + } + else + { + // + // There is no need to taint the + // replies if we have an agent. + // + + control -> TaintReplies = 0; + } + + // + // Be sure that the requests needing a reply + // are flushed immediately. Normal X clients + // use so many replies to make the queuing + // completely useless. + // + + if (control -> SessionMode == session_proxy) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Forcing flush on priority " + << "with a proxy session.\n" + << logofs_flush; + #endif + + control -> FlushPriority = 1; + } + + return 1; +} + +// +// Parameters for MODEM 28.8/33.6/56 Kbps. +// + +int SetLinkModem() +{ + #ifdef TEST + *logofs << "Loop: Setting parameters for MODEM.\n" + << logofs_flush; + #endif + + control -> LinkMode = LINK_TYPE_MODEM; + + control -> TokenSize = 256; + control -> TokenLimit = 24; + + control -> SplitMode = 1; + control -> SplitTotalSize = 128; + control -> SplitTotalStorageSize = 1048576; + + control -> SplitTimeout = 50; + control -> MotionTimeout = 50; + control -> IdleTimeout = 50; + + control -> PackMethod = PACK_ADAPTIVE; + control -> PackQuality = 3; + + return 1; +} + +// +// Parameters for ISDN 64/128 Kbps. +// + +int SetLinkIsdn() +{ + #ifdef TEST + *logofs << "Loop: Setting parameters for ISDN.\n" + << logofs_flush; + #endif + + control -> LinkMode = LINK_TYPE_ISDN; + + control -> TokenSize = 384; + control -> TokenLimit = 24; + + control -> SplitMode = 1; + control -> SplitTotalSize = 128; + control -> SplitTotalStorageSize = 1048576; + + control -> SplitTimeout = 50; + control -> MotionTimeout = 20; + control -> IdleTimeout = 50; + + control -> PackMethod = PACK_ADAPTIVE; + control -> PackQuality = 5; + + return 1; +} + +// +// Parameters for ADSL 256 Kbps. +// + +int SetLinkAdsl() +{ + #ifdef TEST + *logofs << "Loop: Setting parameters for ADSL.\n" + << logofs_flush; + #endif + + control -> LinkMode = LINK_TYPE_ADSL; + + control -> TokenSize = 1536; + control -> TokenLimit = 24; + + control -> SplitMode = 1; + control -> SplitTotalSize = 128; + control -> SplitTotalStorageSize = 1048576; + + control -> SplitTimeout = 50; + control -> MotionTimeout = 10; + control -> IdleTimeout = 50; + + control -> PackMethod = PACK_ADAPTIVE; + control -> PackQuality = 7; + + return 1; +} + +// +// Parameters for XDSL/FDDI/ATM 1/2/34 Mbps WAN. +// + +int SetLinkWan() +{ + #ifdef TEST + *logofs << "Loop: Setting parameters for WAN.\n" + << logofs_flush; + #endif + + control -> LinkMode = LINK_TYPE_WAN; + + control -> TokenSize = 1536; + control -> TokenLimit = 24; + + control -> SplitMode = 1; + control -> SplitTotalSize = 128; + control -> SplitTotalStorageSize = 1048576; + + control -> SplitTimeout = 50; + control -> MotionTimeout = 5; + control -> IdleTimeout = 50; + + control -> PackMethod = PACK_ADAPTIVE; + control -> PackQuality = 9; + + return 1; +} + +// +// Parameters for LAN 10/100 Mbps. +// + +int SetLinkLan() +{ + #ifdef TEST + *logofs << "Loop: Setting parameters for LAN.\n" + << logofs_flush; + #endif + + control -> LinkMode = LINK_TYPE_LAN; + + control -> TokenSize = 1536; + control -> TokenLimit = 24; + + control -> SplitMode = 1; + control -> SplitTotalSize = 128; + control -> SplitTotalStorageSize = 1048576; + + control -> SplitTimeout = 50; + control -> MotionTimeout = 0; + control -> IdleTimeout = 50; + + control -> PackMethod = PACK_ADAPTIVE; + control -> PackQuality = 9; + + return 1; +} + +// +// Identify the requested link type and set +// the control parameters accordingly. +// + +int SetCompression() +{ + if (strcasecmp(linkSpeedName, "modem") == 0) + { + SetCompressionModem(); + } + else if (strcasecmp(linkSpeedName, "isdn") == 0) + { + SetCompressionIsdn(); + } + else if (strcasecmp(linkSpeedName, "adsl") == 0) + { + SetCompressionAdsl(); + } + else if (strcasecmp(linkSpeedName, "wan") == 0) + { + SetCompressionWan(); + } + else if (strcasecmp(linkSpeedName, "lan") == 0) + { + SetCompressionLan(); + } + else + { + return -1; + } + + if (control -> LocalDeltaCompression < 0) + { + control -> LocalDeltaCompression = 1; + } + + // + // If we didn't set remote delta compression + // (as it should always be the case at client + // side) assume value of local side. + // + + if (control -> RemoteDeltaCompression < 0) + { + control -> RemoteDeltaCompression = + control -> LocalDeltaCompression; + } + + // + // If we didn't set remote compression levels + // assume values of local side. + // + + if (control -> RemoteStreamCompression < 0) + { + control -> RemoteStreamCompressionLevel = + control -> LocalStreamCompressionLevel; + + if (control -> RemoteStreamCompressionLevel > 0) + { + control -> RemoteStreamCompression = 1; + } + else + { + control -> RemoteStreamCompression = 0; + } + } + + if (control -> RemoteDataCompression < 0) + { + control -> RemoteDataCompressionLevel = + control -> LocalDataCompressionLevel; + + if (control -> RemoteDataCompressionLevel > 0) + { + control -> RemoteDataCompression = 1; + } + else + { + control -> RemoteDataCompression = 0; + } + } + + return 1; +} + +// +// Compression for MODEM. +// + +int SetCompressionModem() +{ + if (control -> LocalDataCompression < 0) + { + control -> LocalDataCompression = 1; + control -> LocalDataCompressionLevel = 1; + } + + if (control -> LocalDataCompressionThreshold < 0) + { + control -> LocalDataCompressionThreshold = 32; + } + + if (control -> LocalStreamCompression < 0) + { + control -> LocalStreamCompression = 1; + control -> LocalStreamCompressionLevel = 9; + } + + return 1; +} + +// +// Compression for ISDN. +// + +int SetCompressionIsdn() +{ + if (control -> LocalDataCompression < 0) + { + control -> LocalDataCompression = 1; + control -> LocalDataCompressionLevel = 1; + } + + if (control -> LocalDataCompressionThreshold < 0) + { + control -> LocalDataCompressionThreshold = 32; + } + + if (control -> LocalStreamCompression < 0) + { + control -> LocalStreamCompression = 1; + control -> LocalStreamCompressionLevel = 6; + } + + return 1; +} + +// +// Compression for ADSL. +// + +int SetCompressionAdsl() +{ + if (control -> LocalDataCompression < 0) + { + control -> LocalDataCompression = 1; + control -> LocalDataCompressionLevel = 1; + } + + if (control -> LocalDataCompressionThreshold < 0) + { + control -> LocalDataCompressionThreshold = 32; + } + + if (control -> LocalStreamCompression < 0) + { + control -> LocalStreamCompression = 1; + control -> LocalStreamCompressionLevel = 4; + } + + return 1; +} + +// +// Compression for WAN. +// + +int SetCompressionWan() +{ + if (control -> LocalDataCompression < 0) + { + control -> LocalDataCompression = 1; + control -> LocalDataCompressionLevel = 1; + } + + if (control -> LocalDataCompressionThreshold < 0) + { + control -> LocalDataCompressionThreshold = 32; + } + + if (control -> LocalStreamCompression < 0) + { + control -> LocalStreamCompression = 1; + control -> LocalStreamCompressionLevel = 1; + } + + return 1; +} + +// +// Compression for LAN. +// + +int SetCompressionLan() +{ + // + // Disable delta compression if not + // explicitly enabled. + // + + if (control -> LocalDeltaCompression < 0) + { + control -> LocalDeltaCompression = 0; + } + + if (control -> LocalDataCompression < 0) + { + control -> LocalDataCompression = 0; + control -> LocalDataCompressionLevel = 0; + } + + if (control -> LocalDataCompressionThreshold < 0) + { + control -> LocalDataCompressionThreshold = 0; + } + + if (control -> LocalStreamCompression < 0) + { + control -> LocalStreamCompression = 0; + control -> LocalStreamCompressionLevel = 0; + } + + return 1; +} + +int SetLimits() +{ + // + // Check if the user requested strict + // control flow parameters. + // + + if (useStrict == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: LIMIT! Decreasing the token limit " + << "to " << control -> TokenLimit / 2 + << " with option 'strict'.\n" + << logofs_flush; + #endif + + control -> TokenLimit /= 2; + } + + #ifdef STRICT + + control -> TokenLimit = 1; + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: WARNING! LIMIT! Setting the token limit " + << "to " << control -> TokenLimit + << " to simulate the proxy congestion.\n" + << logofs_flush; + #endif + + #endif + + // + // Reduce the size of the log file. + // + + #ifdef QUOTA + + control -> FileSizeLimit = 8388608; + + #endif + + // + // Check the bitrate limits. + // + + if (control -> LocalBitrateLimit == -1) + { + if (control -> ProxyMode == proxy_client) + { + control -> LocalBitrateLimit = + control -> ClientBitrateLimit; + } + else + { + control -> LocalBitrateLimit = + control -> ServerBitrateLimit; + } + } + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: LIMIT! Setting client bitrate limit " + << "to " << control -> ClientBitrateLimit + << " server bitrate limit to " << control -> + ServerBitrateLimit << " with local limit " + << control -> LocalBitrateLimit << ".\n" + << logofs_flush; + #endif + + return 1; +} + +// +// These functions are used to parse literal +// values provided by the user and set the +// control parameters accordingly. +// + +int ParseCacheOption(const char *opt) +{ + int size = ParseArg("", "cache", opt); + + if (size < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value '" + << opt << "' for option 'cache'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value '" + << opt << "' for option 'cache'.\n"; + + return -1; + } + + #ifdef TEST + *logofs << "Loop: Setting size of cache to " + << size << " bytes.\n" << logofs_flush; + #endif + + control -> ClientTotalStorageSize = size; + control -> ServerTotalStorageSize = size; + + strcpy(cacheSizeName, opt); + + if (size == 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Disabling NX delta compression.\n" + << logofs_flush; + #endif + + control -> LocalDeltaCompression = 0; + + #ifdef WARNING + *logofs << "Loop: WARNING! Disabling use of NX persistent cache.\n" + << logofs_flush; + #endif + + control -> PersistentCacheEnableLoad = 0; + control -> PersistentCacheEnableSave = 0; + } + + return 1; +} + +int ParseImagesOption(const char *opt) +{ + int size = ParseArg("", "images", opt); + + if (size < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value '" + << opt << "' for option 'images'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value '" + << opt << "' for option 'images'.\n"; + + return -1; + } + + #ifdef TEST + *logofs << "Loop: Setting size of images cache to " + << size << " bytes.\n" << logofs_flush; + #endif + + control -> ImageCacheDiskLimit = size; + + strcpy(imagesSizeName, opt); + + return 1; +} + +int ParseShmemOption(const char *opt) +{ + int size = ParseArg("", "shseg", opt); + + if (size < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value '" + << opt << "' for option 'shseg'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value '" + << opt << "' for option 'shseg'.\n"; + + return -1; + } + + control -> ShmemClientSize = size; + control -> ShmemServerSize = size; + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Set shared memory size to " + << control -> ShmemServerSize << " bytes.\n" + << logofs_flush; + #endif + + strcpy(shsegSizeName, opt); + + return 1; +} + +int ParseBitrateOption(const char *opt) +{ + int bitrate = ParseArg("", "limit", opt); + + if (bitrate < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid value '" + << opt << "' for option 'limit'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Invalid value '" + << opt << "' for option 'limit'.\n"; + + return -1; + } + + strcpy(bitrateLimitName, opt); + + if (bitrate == 0) + { + #ifdef TEST + *logofs << "Loop: Disabling bitrate limit on proxy link.\n" + << logofs_flush; + #endif + + control -> LocalBitrateLimit = 0; + } + else + { + #ifdef TEST + *logofs << "Loop: Setting bitrate to " << bitrate + << " bits per second.\n" << logofs_flush; + #endif + + // + // Internal representation is in bytes + // per second. + // + + control -> LocalBitrateLimit = bitrate >> 3; + } + + return 1; +} + +int ParseHostOption(const char *opt, char *host, long &port) +{ + #ifdef TEST + *logofs << "Loop: Trying to parse options string '" << opt + << "' as a remote NX host.\n" << logofs_flush; + #endif + + if (opt == NULL || *opt == '\0') + { + #ifdef PANIC + *logofs << "Loop: PANIC! No host parameter provided.\n" + << logofs_flush; + #endif + + return 0; + } + else if (strlen(opt) >= DEFAULT_STRING_LENGTH) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Host parameter exceeds length of " + << DEFAULT_STRING_LENGTH << " characters.\n" + << logofs_flush; + #endif + + return 0; + } + + // + // Look for a host name followed + // by a colon followed by port. + // + + int newPort = port; + + const char *separator = strrchr(opt, ':'); + + if (separator != NULL) + { + const char *check = separator + 1; + + while (*check != '\0' && *check != ',' && + *check != '=' && isdigit(*check) != 0) + { + check++; + } + + newPort = atoi(separator + 1); + + if (newPort < 0 || *check != '\0') + { + #ifdef TEST + *logofs << "Loop: Can't identify remote NX port in string '" + << separator << "'.\n" << logofs_flush; + #endif + + return 0; + } + } + else if (newPort < 0) + { + // + // Complain if port was not passed + // by other means. + // + + #ifdef TEST + *logofs << "Loop: Can't identify remote NX port in string '" + << opt << "'.\n" << logofs_flush; + #endif + + return 0; + } + else + { + separator = opt + strlen(opt); + } + + char newHost[DEFAULT_STRING_LENGTH] = { 0 }; + + strncpy(newHost, opt, strlen(opt) - strlen(separator)); + + *(newHost + strlen(opt) - strlen(separator)) = '\0'; + + const char *check = newHost; + + while (*check != '\0' && *check != ',' && + *check != '=') + { + check++; + } + + if (*check != '\0') + { + #ifdef TEST + *logofs << "Loop: Can't identify remote NX host in string '" + << newHost << "'.\n" << logofs_flush; + #endif + + return 0; + } + else if (*acceptHost != '\0') + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't manage to connect and accept connections " + << "at the same time.\n" << logofs_flush; + + *logofs << "Loop: PANIC! Refusing remote NX host with string '" + << opt << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't manage to connect and accept connections " + << "at the same time.\n"; + + cerr << "Error" << ": Refusing remote NX host with string '" + << opt << "'.\n"; + + return -1; + } + + if (*host != '\0' && strcmp(host, newHost) != 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Overriding remote NX host '" + << host << "' with new value '" << newHost + << "'.\n" << logofs_flush; + #endif + } + + strcpy(host, newHost); + + if (port != -1 && port != newPort) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Overriding remote NX port '" + << port << "' with new value '" << newPort + << "'.\n" << logofs_flush; + #endif + } + + #ifdef TEST + *logofs << "Loop: Parsed options string '" << opt + << "' with host '" << newHost << "' and port '" + << newPort << "'.\n" << logofs_flush; + #endif + + port = newPort; + + return 1; +} + +int ParseFontPath(char *path) +{ + char oldPath[DEFAULT_STRING_LENGTH]; + + strcpy(oldPath, path); + + if (path == NULL || *path == '\0' || strcmp(path, "0") == 0) + { + return 0; + } + + #ifdef TEST + *logofs << "Loop: Parsing font server option '" << path + << "'.\n" << logofs_flush; + #endif + + // + // Convert the value to our default port. + // + + if (strcmp(fontPort, "1") == 0) + { + if (control -> ProxyMode == proxy_server) + { + snprintf(fontPort, DEFAULT_STRING_LENGTH - 1, "%d", + DEFAULT_NX_FONT_PORT_OFFSET + proxyPort); + } + else + { + // + // Let the client use the well-known + // "unix/:7100" font path. + // + + snprintf(fontPort, DEFAULT_STRING_LENGTH - 1, "unix/:7100"); + } + } + + // + // Check if a simple numaric value was given. + // + + if (atoi(path) > 0) + { + #ifdef TEST + *logofs << "Loop: Assuming numeric TCP port '" << atoi(path) + << "' for font server.\n" << logofs_flush; + #endif + + return 1; + } + + // + // Let's assume that a port specification "unix/:7100" + // corresponds to "$TEMP/.font-unix/fs7100" and a port + // "unix/:-1" corresponds to "$TEMP/.font-unix/fs-1". + // + + if (strncmp("unix/:", path, 6) == 0) + { + snprintf(path, DEFAULT_STRING_LENGTH - 1, "%s/.font-unix/fs%s", + control -> TempPath, oldPath + 6); + + *(path + DEFAULT_STRING_LENGTH - 1) = '\0'; + + #ifdef TEST + *logofs << "Loop: Assuming Unix socket '" << path + << "' for font server.\n" << logofs_flush; + #endif + } + else if (strncmp("tcp/:", path, 5) == 0) + { + snprintf(path, DEFAULT_STRING_LENGTH - 1, "%d", atoi(oldPath + 5)); + + *(path + DEFAULT_STRING_LENGTH - 1) = '\0'; + + if (atoi(path) <= 0) + { + goto ParseFontPathError; + } + + #ifdef TEST + *logofs << "Loop: Assuming TCP port '" << atoi(path) + << "' for font server.\n" << logofs_flush; + #endif + } + else + { + // + // Accept an absolute file path as + // a valid Unix socket. + // + + if (*path != '/') + { + goto ParseFontPathError; + } + + #ifdef TEST + *logofs << "Loop: Assuming Unix socket '" << path + << "' for font server.\n" << logofs_flush; + #endif + } + + return 1; + +ParseFontPathError: + + #ifdef TEST + *logofs << "Loop: Unable to determine the font server " + << "port in string '" << path << "'.\n" + << logofs_flush; + #endif + + return -1; +} + +int OpenLogFile(char *name, ostream *&stream) +{ + if (name == NULL || *name == '\0') + { + #ifdef TEST + *logofs << "Loop: WARNING! No name provided for output. Using standard error.\n" + << logofs_flush; + #endif + + if (stream == NULL) + { + stream = &cerr; + } + + return 1; + } + + if (stream == NULL || stream == &cerr) + { + if (*name != '/' && *name != '.') + { + char *filePath = GetSessionPath(); + + if (filePath == NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Cannot determine directory of NX session file.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Cannot determine directory of NX session file.\n"; + + return -1; + } + + if (strlen(filePath) + strlen("/") + + strlen(name) + 1 > DEFAULT_STRING_LENGTH) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Full name of NX file '" << name + << " would exceed length of " << DEFAULT_STRING_LENGTH + << " characters.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Full name of NX file '" << name + << " would exceed length of " << DEFAULT_STRING_LENGTH + << " characters.\n"; + + return -1; + } + + char *file = new char[strlen(filePath) + strlen("/") + + strlen(name) + 1]; + + // + // Transform name in a fully qualified name. + // + + strcpy(file, filePath); + strcat(file, "/"); + strcat(file, name); + + strcpy(name, file); + + delete [] filePath; + delete [] file; + } + + mode_t fileMode = umask(0077); + + for (;;) + { + if ((stream = new ofstream(name, ios::app)) != NULL) + { + break; + } + + usleep(200000); + } + + umask(fileMode); + } + else + { + #ifdef PANIC + *logofs << "Loop: PANIC! Bad stream provided for output.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Bad stream provided for output.\n"; + + return -1; + } + + return 1; +} + +int ReopenLogFile(char *name, ostream *&stream, int limit) +{ + if (*name != '\0' && limit >= 0) + { + struct stat fileStat; + + if (limit > 0) + { + // + // This is used for the log file, if the + // size exceeds the limit. + // + + if (stat(name, &fileStat) != 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Can't get stats of file '" + << name << "'. Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + return 0; + } + else if (fileStat.st_size < (long) limit) + { + return 0; + } + } + + #ifdef TEST + *logofs << "Loop: Deleting file '" << name + << "' with size " << fileStat.st_size + << ".\n" << logofs_flush; + #endif + + // + // Create a new stream over the previous + // file. Trying to delete the file fails + // to work on recent Cygwin installs. + // + + *stream << flush; + + delete stream; + + mode_t fileMode = umask(0077); + + for (;;) + { + if ((stream = new ofstream(name, ios::out)) != NULL) + { + break; + } + + usleep(200000); + } + + umask(fileMode); + + #ifdef TEST + *logofs << "Loop: Reopened file '" << name + << "'.\n" << logofs_flush; + #endif + } + + return 1; +} + +void PrintProcessInfo() +{ + if (agent == NULL) + { + + cerr << endl; + + PrintVersionInfo(); + + cerr << endl; + + cerr << GetCopyrightInfo() + << endl + << GetOtherCopyrightInfo() + << endl + << "See https://github.com/ArcticaProject/nx-libs for more information." << endl << endl; + } + + // + // People get confused by the fact that client + // mode is running on NX server and viceversa. + // Let's adopt an user-friendly naming conven- + // tion here. + // + + cerr << "Info: Proxy running in " + << (control -> ProxyMode == proxy_client ? "client" : "server") + << " mode with pid '" << getpid() << "'.\n"; + + if (agent == NULL) + { + cerr << "Session" << ": Starting session at '" + << strTimestamp() << "'.\n"; + } + + #ifdef TEST + + if (*errorsFileName != '\0') + { + cerr << "Info" << ": Using errors file '" << errorsFileName << "'.\n"; + } + + if (*statsFileName != '\0') + { + cerr << "Info" << ": Using stats file '" << statsFileName << "'.\n"; + } + + #endif +} + +void PrintConnectionInfo() +{ + cerr << "Info" << ": Using " + << linkSpeedName << " link parameters " + << control -> TokenSize + << "/" << control -> TokenLimit + << "/" << control -> FlushPolicy + 1 + << "/" << control -> FlushPriority + << ".\n"; + + if (control -> ProxyMode == proxy_client) + { + cerr << "Info" << ": Using agent parameters " + << control -> PingTimeout + << "/" << control -> MotionTimeout + << "/" << control -> IdleTimeout + << "/" << control -> TaintReplies + << "/" << control -> HideRender + << ".\n"; + } + + if (control -> LocalDeltaCompression == 1) + { + cerr << "Info" << ": Using cache parameters " + << control -> MinimumMessageSize + << "/" << control -> MaximumMessageSize / 1024 << "KB" + << "/" << control -> ClientTotalStorageSize / 1024 << "KB" + << "/" << control -> ServerTotalStorageSize / 1024 << "KB" + << ".\n"; + } + + if (control -> ImageCacheEnableLoad == 1 || + control -> ImageCacheEnableSave == 1) + { + cerr << "Info" << ": Using image streaming parameters " + << control -> SplitTimeout + << "/" << control -> SplitTotalSize + << "/" << control -> SplitTotalStorageSize / 1024 << "KB" + << "/" << control -> SplitDataThreshold + << "/" << control -> SplitDataPacketLimit + << ".\n"; + + cerr << "Info" << ": Using image cache parameters " + << control -> ImageCacheEnableLoad + << "/" << control -> ImageCacheEnableSave + << "/" << control -> ImageCacheDiskLimit / 1024 << "KB" + << ".\n"; + } + + cerr << "Info" << ": Using pack method '" + << packMethodName << "' with session '" + << sessionType << "'.\n"; + + if (*productName != '\0') + { + cerr << "Info" << ": Using product '" << productName + << "'.\n" << logofs_flush; + } + + if (control -> LocalDeltaCompression == 0) + { + cerr << "Info" << ": Not using NX delta compression.\n"; + } + + if (control -> LocalDataCompression == 1 || + control -> RemoteDataCompression == 1) + { + cerr << "Info" << ": Using ZLIB data compression " + << control -> LocalDataCompressionLevel + << "/" << control -> RemoteDataCompressionLevel + << "/" << control -> LocalDataCompressionThreshold + << ".\n"; + } + else + { + cerr << "Info" << ": Not using ZLIB data compression.\n"; + } + + if (control -> LocalStreamCompression == 1 || + control -> RemoteStreamCompression == 1) + { + cerr << "Info" << ": Using ZLIB stream compression " + << control -> LocalStreamCompressionLevel + << "/" << control -> RemoteStreamCompressionLevel + << ".\n"; + } + else + { + cerr << "Info" << ": Not using ZLIB stream compression.\n"; + } + + if (control -> LocalBitrateLimit > 0) + { + cerr << "Info" << ": Using bandwidth limit of " + << bitrateLimitName << " bits per second.\n"; + } + + if (control -> PersistentCacheName != NULL) + { + cerr << "Info" << ": Using cache file '" + << control -> PersistentCachePath << "/" + << control -> PersistentCacheName << "'.\n"; + } + else + { + if (control -> PersistentCacheEnableLoad == 0 || + control -> LocalDeltaCompression == 0) + { + cerr << "Info" << ": Not using a persistent cache.\n"; + } + else + { + cerr << "Info" << ": No suitable cache file found.\n"; + } + } + + if (control -> ProxyMode == proxy_client && + (useUnixSocket > 0 || useTcpSocket > 0 || + useAgentSocket > 0)) + { + cerr << "Info" << ": Listening to X11 connections " + << "on display ':" << xPort << "'.\n"; + } + else if (control -> ProxyMode == proxy_server) + { + cerr << "Info" << ": Forwarding X11 connections " + << "to display '" << displayHost << "'.\n"; + } + + if (control -> ProxyMode == proxy_client && + useCupsSocket > 0 && cupsPort.enabled()) + { + cerr << "Info" << ": Listening to CUPS connections " + << "on port '" << cupsPort << "'.\n"; + } + else if (control -> ProxyMode == proxy_server && + cupsPort.enabled()) + { + cerr << "Info" << ": Forwarding CUPS connections " + << "to port '" << cupsPort << "'.\n"; + } + + if (control -> ProxyMode == proxy_client && + useAuxSocket > 0 && auxPort.enabled()) + { + cerr << "Info" << ": Listening to auxiliary X11 connections " + << "on port '" << auxPort << "'.\n"; + } + else if (control -> ProxyMode == proxy_server && + auxPort.enabled()) + { + cerr << "Info" << ": Forwarding auxiliary X11 connections " + << "to display '" << displayHost << "'.\n"; + } + + if (control -> ProxyMode == proxy_client && + useSmbSocket > 0 && smbPort.enabled()) + { + cerr << "Info" << ": Listening to SMB connections " + << "on port '" << smbPort << "'.\n"; + } + else if (control -> ProxyMode == proxy_server && + smbPort.enabled()) + { + cerr << "Info" << ": Forwarding SMB connections " + << "to port '" << smbPort << "'.\n"; + } + + if (control -> ProxyMode == proxy_client && + useMediaSocket > 0 && mediaPort.enabled()) + { + cerr << "Info" << ": Listening to multimedia connections " + << "on port '" << mediaPort << "'.\n"; + } + else if (control -> ProxyMode == proxy_server && + mediaPort.enabled()) + { + cerr << "Info" << ": Forwarding multimedia connections " + << "to port '" << mediaPort << "'.\n"; + } + + if (control -> ProxyMode == proxy_client && + useHttpSocket > 0 && httpPort.enabled()) + { + cerr << "Info" << ": Listening to HTTP connections " + << "on port '" << httpPort << "'.\n"; + } + else if (control -> ProxyMode == proxy_server && + httpPort.enabled()) + { + cerr << "Info" << ": Forwarding HTTP connections " + << "to port '" << httpPort << "'.\n"; + } + + if (control -> ProxyMode == proxy_server && + useFontSocket > 0 && *fontPort != '\0') + { + cerr << "Info" << ": Listening to font server connections " + << "on port '" << fontPort << "'.\n"; + } + else if (control -> ProxyMode == proxy_client && + *fontPort != '\0') + { + cerr << "Info" << ": Forwarding font server connections " + << "to port '" << fontPort << "'.\n"; + } + + if (useSlaveSocket > 0 && slavePort.enabled()) + { + cerr << "Info" << ": Listening to slave connections " + << "on port '" << slavePort << "'.\n"; + } +} + +void PrintVersionInfo() +{ + cerr << "NXPROXY - " << "Version " + << control -> LocalVersionMajor << "." + << control -> LocalVersionMinor << "." + << control -> LocalVersionPatch << "." + << control -> LocalVersionMaintenancePatch; + + cerr << endl; +} + +void PrintCopyrightInfo() +{ + cerr << endl; + + PrintVersionInfo(); + + cerr << endl; + + cerr << GetCopyrightInfo(); + + // + // Print third party's copyright info. + // + + cerr << endl; + + cerr << GetOtherCopyrightInfo(); + + cerr << endl; +} + +void PrintOptionIgnored(const char *type, const char *name, const char *value) +{ + if (control -> ProxyMode == proxy_server) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Ignoring " << type + << " option '" << name << "' with value '" + << value << "' at " << "NX client side.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Ignoring " << type + << " option '" << name << "' with value '" + << value << "' at " << "NX client side.\n"; + } + else + { + #ifdef WARNING + *logofs << "Loop: WARNING! Ignoring " << type + << " option '" << name << "' with value '" + << value << "' at " << "NX server side.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Ignoring " << type + << " option '" << name << "' with value '" + << value << "' at " << "NX server side.\n"; + } +} + +const char *GetOptions(const char *options) +{ + if (options != NULL) + { + if (strncasecmp(options, "nx/nx,", 6) != 0 && + strncasecmp(options, "nx,", 3) != 0 && + strncasecmp(options, "nx:", 3) != 0) + { + #ifdef TEST + *logofs << "Loop: PANIC! Display options string '" << options + << "' must start with 'nx' or 'nx/nx' prefix.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Display options string '" << options + << "' must start with 'nx' or 'nx/nx' prefix.\n"; + + HandleCleanup(); + } + } + else + { + options = getenv("DISPLAY"); + } + + return options; +} + +const char *GetArg(int &argi, int argc, const char **argv) +{ + // + // Skip "-" and flag character. + // + + const char *arg = argv[argi] + 2; + + if (*arg == 0) + { + if (argi + 1 == argc) + { + return NULL; + } + else + { + argi++; + + return (*argv[argi] == '-' ? NULL : argv[argi]); + } + } + else + { + return (*arg == '-' ? NULL : arg); + } +} + +int CheckArg(const char *type, const char *name, const char *value) +{ + #ifdef TEST + *logofs << "Loop: Parsing " << type << " option '" << name + << "' with value '" << (value ? value : "(null)") + << "'.\n" << logofs_flush; + #endif + + if (value == NULL || strstr(value, "=") != NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error in " << type << " option '" + << name << "'. No value found.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error in " << type << " option '" + << name << "'. No value found.\n"; + + return -1; + } + else if (strstr(name, ",") != NULL) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Parse error at " << type << " option '" + << name << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Parse error at " << type << " option '" + << name << "'.\n"; + + return -1; + } + else if (strlen(value) >= DEFAULT_STRING_LENGTH) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Value '" << value << "' of " + << type << " option '" << name << "' exceeds length of " + << DEFAULT_STRING_LENGTH << " characters.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Value '" << value << "' of " + << type << " option '" << name << "' exceeds length of " + << DEFAULT_STRING_LENGTH << " characters.\n"; + + return -1; + } + + return 1; +} + +int ParseArg(const char *type, const char *name, const char *value) +{ + if (strcasecmp(value, "0") == 0) + { + return 0; + } + + // + // Find the base factor. + // + + double base; + + const char *id = value + strlen(value) - 1; + + if (strcasecmp(id, "g") == 0) + { + base = 1024 * 1024 * 1024; + } + else if (strcasecmp(id, "m") == 0) + { + base = 1024 * 1024; + } + else if (strcasecmp(id, "k") == 0) + { + base = 1024; + } + else if (strcasecmp(id, "b") == 0 || isdigit(*id) == 1) + { + base = 1; + } + else + { + return -1; + } + + char *string = new char[strlen(value)]; + + strncpy(string, value, strlen(value) - 1); + + *(string + (strlen(value) - 1)) = '\0'; + + #ifdef TEST + + *logofs << "Loop: Parsing integer option '" << name + << "' from string '" << string << "' with base set to "; + + switch (tolower(*id)) + { + case 'k': + case 'm': + case 'g': + { + *logofs << (char) toupper(*id); + } + break; + } + + *logofs << ".\n" << logofs_flush; + + #endif + + double result = atof(string) * base; + + if (result < 0 || result > (((unsigned) -1) >> 1)) + { + delete [] string; + + return -1; + } + + delete [] string; + + #ifdef TEST + *logofs << "Loop: Integer option parsed to '" + << (int) result << "'.\n" << logofs_flush; + #endif + + return (int) result; +} + +void SetAndValidateChannelEndPointArg(const char *type, const char *name, const char *value, + ChannelEndPoint &endPoint) { + endPoint.setSpec(value); + if (!endPoint.validateSpec()) { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid " << type + << " option '" << name << "' with value '" + << value << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid " << type + << " option '" << name << "' with value '" + << value << "'.\n"; + + HandleCleanup(); + } +} + + +int ValidateArg(const char *type, const char *name, const char *value) +{ + int number = atoi(value); + + if (number < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid " << type + << " option '" << name << "' with value '" + << value << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid " << type + << " option '" << name << "' with value '" + << value << "'.\n"; + + HandleCleanup(); + } + + return number; +} + +int LowercaseArg(const char *type, const char *name, char *value) +{ + char *next = value; + + while (*next != '\0') + { + *next = tolower(*next); + + next++; + } + + return 1; +} + +int CheckSignal(int signal) +{ + // + // Return 1 if the signal needs to be handled + // by the proxy, 2 if the signal just needs to + // be blocked to avoid interrupting a system + // call. + // + + switch (signal) + { + case SIGCHLD: + case SIGUSR1: + case SIGUSR2: + case SIGHUP: + case SIGINT: + case SIGTERM: + case SIGPIPE: + case SIGALRM: + { + return 1; + } + case SIGVTALRM: + case SIGWINCH: + case SIGIO: + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + { + return 2; + } + default: + { + #ifdef __CYGWIN32__ + + // + // This signal can be raised by the Cygwin + // library. + // + + if (signal == 12) + { + return 1; + } + + #endif + + return 0; + } + } +} + +static void PrintUsageInfo(const char *option, int error) +{ + if (error == 1) + { + cerr << "Error" << ": Invalid command line option '" << option << "'.\n"; + } + + cerr << GetUsageInfo(); + + if (error == 1) + { + cerr << "Error" << ": NX transport initialization failed.\n"; + } +} + +static void handleCheckSessionInLoop() +{ + // + // Check if we completed the shutdown procedure + // and the remote confirmed the shutdown. The + // tear down should be always initiated by the + // agent, but the X server side may unilateral- + // ly shut down the link without our permission. + // + + if (proxy -> getShutdown() > 0) + { + #ifdef TEST + *logofs << "Loop: End of NX transport requested " + << "by remote.\n" << logofs_flush; + #endif + + handleTerminatingInLoop(); + + if (control -> ProxyMode == proxy_server) + { + #ifdef TEST + *logofs << "Loop: Bytes received so far are " + << (unsigned long long) statistics -> getBytesIn() + << ".\n" << logofs_flush; + #endif + + if (statistics -> getBytesIn() < 1024) + { + cerr << "Info" << ": Your session was closed before reaching " + << "a usable state.\n"; + cerr << "Info" << ": This can be due to the local X server " + << "refusing access to the client.\n"; + cerr << "Info" << ": Please check authorization provided " + << "by the remote X application.\n"; + } + } + + #ifdef TEST + *logofs << "Loop: Shutting down the NX transport.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } + else if (proxy -> handlePing() < 0) + { + #ifdef TEST + *logofs << "Loop: Failure handling the ping for " + << "proxy FD#" << proxyFD << ".\n" + << logofs_flush; + #endif + + HandleShutdown(); + } + + // + // Check if the watchdog has exited and we didn't + // get the SIGCHLD. This can happen if the parent + // has overridden our signal handlers. + // + + if (IsRunning(lastWatchdog) && CheckProcess(lastWatchdog, "watchdog") == 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Watchdog is gone unnoticed. " + << "Setting the last signal to SIGTERM.\n" + << logofs_flush; + #endif + + lastSignal = SIGTERM; + + #ifdef WARNING + *logofs << "Loop: WARNING! Resetting pid of last " + << "watchdog process.\n" << logofs_flush; + #endif + + SetNotRunning(lastWatchdog); + } + + // + // Let the client proxy find out if the agent's + // channel is gone. This is the normal shutdown + // procedure in the case of an internal connect- + // ion to the agent. + // + + int cleanup = 0; + + if (control -> ProxyMode == proxy_client && + agent != NULL && proxy -> getType(agentFD[1]) == + channel_none && lastKill == 0 && lastDestroy == 1) + { + #ifdef TEST + *logofs << "Loop: End of NX transport requested " + << "by agent.\n" << logofs_flush; + #endif + + #ifdef TEST + *logofs << "Loop: Bytes sent so far are " + << (unsigned long long) statistics -> getBytesOut() + << ".\n" << logofs_flush; + #endif + + if (statistics -> getBytesOut() < 1024) + { + cerr << "Info" << ": Your session has died before reaching " + << "an usable state.\n"; + cerr << "Info" << ": This can be due to the remote X server " + << "refusing access to the client.\n"; + cerr << "Info" << ": Please check the authorization provided " + << "by your X application.\n"; + } + + cleanup = 1; + } + + // + // Check if the user requested the end of the + // session by sending a signal to the proxy. + // All signals are handled in the main loop + // so we need to reset the value to get ready + // for the next iteration. + // + + int signal = 0; + + if (lastSignal != 0) + { + switch (lastSignal) + { + case SIGCHLD: + case SIGUSR1: + case SIGUSR2: + { + break; + } + default: + { + signal = lastSignal; + + cleanup = 1; + + break; + } + } + + lastSignal = 0; + } + + if (cleanup == 1) + { + // + // The first time termination signal is received + // disable all further connections, close down any + // X channel and wait for a second signal. + // + + if (lastKill == 0) + { + // + // Don't print a message if cleanup is + // due to normal termination of agent. + // + + if (signal != 0) + { + #ifdef TEST + *logofs << "Loop: End of NX transport requested by signal '" + << signal << "' '" << DumpSignal(signal) + << "'.\n" << logofs_flush; + #endif + + handleTerminatingInLoop(); + } + + // + // Disable any further connection. + // + + CleanupListeners(); + + // + // Close all the remaining X channels and + // let proxies save their persistent cache + // on disk. + // + + CleanupConnections(); + + // + // We'll need to wait for the X channels + // to be shut down before waiting for the + // cleanup signal. + // + + lastKill = 1; + } + else if (lastKill == 2) + { + #ifdef TEST + *logofs << "Loop: Shutting down the NX transport.\n" + << logofs_flush; + #endif + + proxy -> handleShutdown(); + + HandleCleanup(); + } + } + + if (lastKill == 1 && proxy -> getChannels(channel_x11) == 0) + { + // + // Save the message stores to the + // persistent cache. + // + + proxy -> handleSave(); + + // + // Run a watchdog process so we can finally + // give up at the time the watchdog exits. + // + + if (IsNotRunning(lastWatchdog)) + { + int timeout = control -> CleanupTimeout; + + if (timeout > 0) + { + if (proxy -> getChannels() == 0) + { + timeout = 500; + } + + #ifdef TEST + *logofs << "Loop: Starting watchdog process with timeout " + << "of " << timeout << " Ms.\n" + << logofs_flush; + #endif + } + #ifdef TEST + else + { + *logofs << "Loop: Starting watchdog process without " + << "a timeout.\n" << logofs_flush; + } + #endif + + lastWatchdog = NXTransWatchdog(timeout); + + if (IsFailed(lastWatchdog)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't start the NX watchdog " + << "process in shutdown.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't start the NX watchdog " + << "process in shutdown.\n"; + + HandleCleanup(); + } + #ifdef TEST + else + { + *logofs << "Loop: Watchdog started with pid '" + << lastWatchdog << "'.\n" << logofs_flush; + } + #endif + } + else + { + #ifdef PANIC + *logofs << "Loop: PANIC! Previous watchdog detected " + << "in shutdown with pid '" << lastWatchdog + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Previous watchdog detected " + << "in shutdown with pid '" << lastWatchdog + << "'.\n"; + + HandleCleanup(); + } + + if (control -> CleanupTimeout > 0) + { + #ifdef TEST + *logofs << "Loop: Waiting the cleanup timeout to complete.\n" + << logofs_flush; + #endif + + cerr << "Info" << ": Waiting the cleanup timeout to complete.\n"; + } + else + { + // + // The NX server will kill the watchdog + // process after having shut down the + // service channels. + // + + cerr << "Info" << ": Watchdog running with pid '" << lastWatchdog + << "'.\n"; + + #ifdef TEST + *logofs << "Loop: Waiting the watchdog process to complete.\n" + << logofs_flush; + #endif + + cerr << "Info" << ": Waiting the watchdog process to complete.\n"; + } + + lastKill = 2; + } +} + +static void handleCheckBitrateInLoop() +{ + static long int slept = 0; + + #ifdef TEST + *logofs << "Loop: Bitrate is " << statistics -> getBitrateInShortFrame() + << " B/s and " << statistics -> getBitrateInLongFrame() + << " B/s in " << control -> ShortBitrateTimeFrame / 1000 + << "/" << control -> LongBitrateTimeFrame / 1000 + << " seconds timeframes.\n" << logofs_flush; + #endif + + // + // This can be improved. We may not jump out + // of the select often enough to guarantee + // the necessary accuracy. + // + + if (control -> LocalBitrateLimit > 0) + { + #ifdef TEST + *logofs << "Loop: Calculating bandwidth usage with limit " + << control -> LocalBitrateLimit << ".\n" + << logofs_flush; + #endif + + int reference = (statistics -> getBitrateInLongFrame() + + statistics -> getBitrateInShortFrame()) / 2; + + if (reference > control -> LocalBitrateLimit) + { + double ratio = ((double) reference) / + ((double) control -> LocalBitrateLimit); + + if (ratio > 1.2) + { + ratio = 1.2; + } + + slept += (unsigned int) (pow(50000, ratio) / 1000); + + if (slept > 2000) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Sleeping due to " + << "reference bitrate of " << reference + << " B/s.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Sleeping due to " + << "reference bitrate of " << reference + << " B/s.\n"; + + slept %= 2000; + } + + T_timestamp idleTs = getNewTimestamp(); + + usleep((unsigned int) pow(50000, ratio)); + + int diffTs = diffTimestamp(idleTs, getNewTimestamp()); + + statistics -> addIdleTime(diffTs); + + statistics -> subReadTime(diffTs); + } + } +} + +#if defined(TEST) || defined(INFO) + +static void handleCheckStateInLoop(int &setFDs) +{ + int fdLength; + int fdPending; + int fdSplits; + + for (int j = 0; j < setFDs; j++) + { + if (j != proxyFD) + { + fdPending = proxy -> getPending(j); + + if (fdPending > 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Buffer for descriptor FD#" + << j << " has pending bytes to read.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } + + fdLength = proxy -> getLength(j); + + if (fdLength > 0) + { + #ifdef TEST + *logofs << "Loop: WARNING! Buffer for descriptor FD#" + << j << " has " << fdLength << " bytes to write.\n" + << logofs_flush; + #endif + } + } + } + + fdPending = proxy -> getPending(proxyFD); + + if (fdPending > 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Buffer for proxy descriptor FD#" + << proxyFD << " has pending bytes to read.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } + + fdLength = proxy -> getFlushable(proxyFD); + + if (fdLength > 0) + { + if (control -> FlushPolicy == policy_immediate && + proxy -> getBlocked(proxyFD) == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Buffer for proxy descriptor FD#" + << proxyFD << " has " << fdLength << " bytes " + << "to write with policy 'immediate'.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } + else + { + #ifdef TEST + *logofs << "Loop: WARNING! Buffer for proxy descriptor FD#" + << proxyFD << " has " << fdLength << " bytes " + << "to write.\n" << logofs_flush; + #endif + } + } + + fdSplits = proxy -> getSplitSize(); + + if (fdSplits > 0) + { + #ifdef WARNING + *logofs << "Loop: WARNING! Proxy descriptor FD#" << proxyFD + << " has " << fdSplits << " splits to send.\n" + << logofs_flush; + #endif + } +} + +static void handleCheckSelectInLoop(int &setFDs, fd_set &readSet, + fd_set &writeSet, T_timestamp selectTs) +{ + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Maximum descriptors is [" + << setFDs << "] at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + int i; + + if (setFDs > 0) + { + i = 0; + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Selected for read are "; + #endif + + for (int j = 0; j < setFDs; j++) + { + if (FD_ISSET(j, &readSet)) + { + #if defined(TEST) || defined(INFO) + *logofs << "[" << j << "]" << logofs_flush; + #endif + + i++; + } + } + + if (i > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << ".\n" << logofs_flush; + #endif + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "[none].\n" << logofs_flush; + #endif + } + + i = 0; + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Selected for write are "; + #endif + + for (int j = 0; j < setFDs; j++) + { + if (FD_ISSET(j, &writeSet)) + { + #if defined(TEST) || defined(INFO) + *logofs << "[" << j << "]" << logofs_flush; + #endif + + i++; + } + } + + if (i > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << ".\n" << logofs_flush; + #endif + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "[none].\n" << logofs_flush; + #endif + } + } + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Select timeout is " + << selectTs.tv_sec << " S and " + << (double) selectTs.tv_usec / 1000 + << " Ms.\n" << logofs_flush; + #endif +} + +static void handleCheckResultInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, + fd_set &writeSet, struct timeval &selectTs, + struct timeval &startTs) +{ + int diffTs = diffTimestamp(startTs, getNewTimestamp()); + + #if defined(TEST) || defined(INFO) + + if (diffTs >= (control -> PingTimeout - + (control -> LatencyTimeout * 4))) + { + *logofs << "Loop: Select result is [" << resultFDs + << "] at " << strMsTimestamp() << " with no " + << "communication within " << diffTs + << " Ms.\n" << logofs_flush; + } + else + { + *logofs << "Loop: Select result is [" << resultFDs + << "] error is [" << errorFDs << "] at " + << strMsTimestamp() << " after " << diffTs + << " Ms.\n" << logofs_flush; + } + + #endif + + int i; + + if (resultFDs > 0) + { + i = 0; + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Selected for read are "; + #endif + + for (int j = 0; j < setFDs; j++) + { + if (FD_ISSET(j, &readSet)) + { + #if defined(TEST) || defined(INFO) + *logofs << "[" << j << "]" << logofs_flush; + #endif + + i++; + } + } + + if (i > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << ".\n" << logofs_flush; + #endif + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "[none].\n" << logofs_flush; + #endif + } + + i = 0; + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Selected for write are "; + #endif + + for (int j = 0; j < setFDs; j++) + { + if (FD_ISSET(j, &writeSet)) + { + #if defined(TEST) || defined(INFO) + *logofs << "[" << j << "]" << logofs_flush; + #endif + + i++; + } + } + + if (i > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << ".\n" << logofs_flush; + #endif + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "[none].\n" << logofs_flush; + #endif + } + } +} + +#endif + +static void handleCheckSessionInConnect() +{ + #ifdef TEST + *logofs << "Loop: Going to check session in connect.\n" + << logofs_flush; + #endif + + if (control -> ProxyMode == proxy_client) + { + HandleAlert(FAILED_PROXY_CONNECTION_CLIENT_ALERT, 1); + } + else if (IsNotRunning(lastDialog)) + { + HandleAlert(FAILED_PROXY_CONNECTION_SERVER_ALERT, 1); + } + + handleAlertInLoop(); +} + +static void handleStatisticsInLoop() +{ + if (lastSignal == 0) + { + return; + } + + int mode = NO_STATS; + + if (control -> EnableStatistics == 1) + { + if (lastSignal == SIGUSR1) + { + // + // Print overall statistics. + // + + mode = TOTAL_STATS; + } + else if (lastSignal == SIGUSR2) + { + // + // Print partial statistics. + // + + mode = PARTIAL_STATS; + } + + if (mode == TOTAL_STATS || mode == PARTIAL_STATS) + { + #ifdef TEST + *logofs << "Loop: Going to request proxy statistics " + << "with signal '" << DumpSignal(lastSignal) + << "'.\n" << logofs_flush; + #endif + + if (proxy != NULL) + { + if (ReopenLogFile(statsFileName, statofs, 0) < 0) + { + HandleCleanup(); + } + + proxy -> handleStatistics(mode, statofs); + } + } + } +} + +static void handleNegotiationInLoop(int &setFDs, fd_set &readSet, + fd_set &writeSet, T_timestamp &selectTs) +{ + int yield = 0; + + while (yield == 0) + { + #ifdef TEST + *logofs << "Loop: Going to run a new negotiation loop " + << "with stage " << control -> ProxyStage + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + switch (control -> ProxyStage) + { + case stage_undefined: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_undefined" << "'.\n" + << logofs_flush; + #endif + + control -> ProxyStage = stage_initializing; + + break; + } + case stage_initializing: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_initializing" << "'.\n" + << logofs_flush; + #endif + + InitBeforeNegotiation(); + + control -> ProxyStage = stage_connecting; + + break; + } + case stage_connecting: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_connecting" << "'.\n" + << logofs_flush; + #endif + + SetupProxyConnection(); + + control -> ProxyStage = stage_connected; + + break; + } + case stage_connected: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_connected" << "'.\n" + << logofs_flush; + #endif + + // + // Server side proxy must always be the one that + // sends its version and options first, so, in + // some way, client side can be the the one that + // has the last word on the matter. + // + + if (control -> ProxyMode == proxy_server) + { + // + // Check if we have been listening for a + // forwarder. In this case it will have to + // authenticate itself. + // + + if (WE_LISTEN_FORWARDER) + { + control -> ProxyStage = stage_waiting_forwarder_version; + + break; + } + + control -> ProxyStage = stage_sending_proxy_options; + } + else + { + // + // The X client side is the side that has to wait + // for the authorization cookie and any remote + // option. + // + + control -> ProxyStage = stage_waiting_proxy_version; + } + + break; + } + case stage_sending_proxy_options: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_sending_proxy_options" << "'.\n" + << logofs_flush; + #endif + + if (SendProxyOptions(proxyFD) < 0) + { + goto handleNegotiationInLoopError; + } + + if (control -> ProxyMode == proxy_server) + { + control -> ProxyStage = stage_waiting_proxy_version; + } + else + { + control -> ProxyStage = stage_sending_proxy_caches; + } + + break; + } + case stage_waiting_forwarder_version: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_waiting_forwarder_version" << "'.\n" + << logofs_flush; + #endif + + int result = ReadForwarderVersion(proxyFD); + + if (result == 0) + { + yield = 1; + } + else if (result == 1) + { + control -> ProxyStage = stage_waiting_forwarder_options; + } + else + { + goto handleNegotiationInLoopError; + } + + break; + } + case stage_waiting_forwarder_options: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_waiting_forwarder_options" << "'.\n" + << logofs_flush; + #endif + + int result = ReadForwarderOptions(proxyFD); + + if (result == 0) + { + yield = 1; + } + else if (result == 1) + { + control -> ProxyStage = stage_sending_proxy_options; + } + else + { + goto handleNegotiationInLoopError; + } + + break; + } + case stage_waiting_proxy_version: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_waiting_proxy_version" << "'.\n" + << logofs_flush; + #endif + + int result = ReadProxyVersion(proxyFD); + + if (result == 0) + { + yield = 1; + } + else if (result == 1) + { + control -> ProxyStage = stage_waiting_proxy_options; + } + else + { + goto handleNegotiationInLoopError; + } + + break; + } + case stage_waiting_proxy_options: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_waiting_proxy_options" << "'.\n" + << logofs_flush; + #endif + + int result = ReadProxyOptions(proxyFD); + + if (result == 0) + { + yield = 1; + } + else if (result == 1) + { + if (control -> ProxyMode == proxy_server) + { + control -> ProxyStage = stage_waiting_proxy_caches; + } + else + { + control -> ProxyStage = stage_sending_proxy_options; + } + } + else + { + goto handleNegotiationInLoopError; + } + + break; + } + case stage_sending_proxy_caches: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_sending_proxy_caches" << "'.\n" + << logofs_flush; + #endif + + if (SendProxyCaches(proxyFD) < 0) + { + goto handleNegotiationInLoopError; + } + + if (control -> ProxyMode == proxy_server) + { + control -> ProxyStage = stage_operational; + } + else + { + control -> ProxyStage = stage_waiting_proxy_caches; + } + + break; + } + case stage_waiting_proxy_caches: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_waiting_proxy_caches" << "'.\n" + << logofs_flush; + #endif + + int result = ReadProxyCaches(proxyFD); + + if (result == 0) + { + yield = 1; + } + else if (result == 1) + { + if (control -> ProxyMode == proxy_server) + { + control -> ProxyStage = stage_sending_proxy_caches; + } + else + { + control -> ProxyStage = stage_operational; + } + } + else + { + goto handleNegotiationInLoopError; + } + + break; + } + case stage_operational: + { + #ifdef TEST + *logofs << "Loop: Handling negotiation with '" + << "stage_operational" << "'.\n" + << logofs_flush; + #endif + + InitAfterNegotiation(); + + yield = 1; + + break; + } + default: + { + #ifdef PANIC + *logofs << "Loop: PANIC! Unmanaged case '" << control -> ProxyStage + << "' while handling negotiation.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unmanaged case '" << control -> ProxyStage + << "' while handling negotiation.\n"; + + HandleCleanup(); + } + } + } + + // + // Check if the user requested the end of + // the session. + // + + if (CheckAbort() != 0) + { + HandleCleanup(); + } + + // + // Select the proxy descriptor so that we + // can proceed negotiating the session. + // + + FD_SET(proxyFD, &readSet); + + if (proxyFD >= setFDs) + { + setFDs = proxyFD + 1; + } + + setMinTimestamp(selectTs, control -> PingTimeout); + + #ifdef TEST + *logofs << "Loop: Selected proxy FD#" << proxyFD << " in negotiation " + << "phase with timeout of " << selectTs.tv_sec << " S and " + << selectTs.tv_usec << " Ms.\n" << logofs_flush; + #endif + + return; + +handleNegotiationInLoopError: + + #ifdef PANIC + *logofs << "Loop: PANIC! Failure negotiating the session in stage '" + << control -> ProxyStage << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failure negotiating the session in stage '" + << control -> ProxyStage << "'.\n"; + + + if (control -> ProxyMode == proxy_server && + control -> ProxyStage == stage_waiting_proxy_version) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Wrong version or invalid session " + << "authentication cookie.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Wrong version or invalid session " + << "authentication cookie.\n"; + } + + handleTerminatingInLoop(); + + HandleCleanup(); +} + +static void handleTerminatingInLoop() +{ + if (getpid() == lastProxy) + { + if (control -> ProxyStage < stage_terminating) + { + if (agent == NULL) + { + cerr << "Session" << ": Terminating session at '" + << strTimestamp() << "'.\n"; + } + + control -> ProxyStage = stage_terminating; + } + } +} + +static void handleTerminatedInLoop() +{ + if (getpid() == lastProxy) + { + if (control -> ProxyStage < stage_terminated) + { + if (agent == NULL) + { + cerr << "Session" << ": Session terminated at '" + << strTimestamp() << "'.\n"; + } + + control -> ProxyStage = stage_terminated; + } + } +} + +static void handleAlertInLoop() +{ + if (lastAlert.code == 0) + { + return; + } + + // + // Since ProtoStep7 (#issue 108) + // + // Now the remote proxy should always + // be able to handle the alert + // + + if (lastAlert.local == 0) + { + if (proxy != NULL) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Requesting a remote alert with code '" + << lastAlert.code << "'.\n" << logofs_flush; + #endif + + if (proxy -> handleAlert(lastAlert.code) < 0) + { + HandleShutdown(); + } + } + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Handling a local alert with code '" + << lastAlert.code << "'.\n" << logofs_flush; + #endif + + if (control -> ProxyMode == proxy_client) + { + // + // If we are at X client side and server + // proxy is not responding, we don't have + // any possibility to interact with user. + // + + if (lastAlert.code != CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT && + lastAlert.code != RESTART_DEAD_PROXY_CONNECTION_CLIENT_ALERT && + lastAlert.code != FAILED_PROXY_CONNECTION_CLIENT_ALERT) + { + // + // Let the server proxy show the dialog. + // + + if (proxy != NULL && + proxy -> handleAlert(lastAlert.code) < 0) + { + HandleShutdown(); + } + } + } + else + { + char caption[DEFAULT_STRING_LENGTH]; + + strcpy(caption, ALERT_CAPTION_PREFIX); + + int length = strlen(sessionId); + + // + // Get rid of the trailing MD5 from session id. + // + + if (length > (MD5_LENGTH * 2 + 1) && + *(sessionId + (length - (MD5_LENGTH * 2 + 1))) == '-') + { + strncat(caption, sessionId, length - (MD5_LENGTH * 2 + 1)); + } + else + { + strcat(caption, sessionId); + } + + // + // Use the display to which we are forwarding + // the remote X connections. + // + + char *display = displayHost; + + int replace = 1; + int local = 1; + + const char *message; + const char *type; + + switch (lastAlert.code) + { + case CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT: + { + message = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_STRING; + type = CLOSE_DEAD_X_CONNECTION_CLIENT_ALERT_TYPE; + + break; + } + case CLOSE_DEAD_X_CONNECTION_SERVER_ALERT: + { + message = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_STRING; + type = CLOSE_DEAD_X_CONNECTION_SERVER_ALERT_TYPE; + + break; + } + case CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT: + { + message = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING; + type = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE; + + break; + } + case RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT: + { + message = RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_STRING; + type = RESTART_DEAD_PROXY_CONNECTION_SERVER_ALERT_TYPE; + + break; + } + case CLOSE_UNRESPONSIVE_X_SERVER_ALERT: + { + message = CLOSE_UNRESPONSIVE_X_SERVER_ALERT_STRING; + type = CLOSE_UNRESPONSIVE_X_SERVER_ALERT_TYPE; + + break; + } + case WRONG_PROXY_VERSION_ALERT: + { + message = WRONG_PROXY_VERSION_ALERT_STRING; + type = WRONG_PROXY_VERSION_ALERT_TYPE; + + break; + } + case FAILED_PROXY_CONNECTION_SERVER_ALERT: + { + message = FAILED_PROXY_CONNECTION_SERVER_ALERT_STRING; + type = FAILED_PROXY_CONNECTION_SERVER_ALERT_TYPE; + + break; + } + case MISSING_PROXY_CACHE_ALERT: + { + message = MISSING_PROXY_CACHE_ALERT_STRING; + type = MISSING_PROXY_CACHE_ALERT_TYPE; + + break; + } + case ABORT_PROXY_CONNECTION_ALERT: + { + message = ABORT_PROXY_CONNECTION_ALERT_STRING; + type = ABORT_PROXY_CONNECTION_ALERT_TYPE; + + break; + } + case DISPLACE_MESSAGE_ALERT: + { + message = DISPLACE_MESSAGE_ALERT_STRING; + type = DISPLACE_MESSAGE_ALERT_TYPE; + + break; + } + case GREETING_MESSAGE_ALERT: + { + message = GREETING_MESSAGE_ALERT_STRING; + type = GREETING_MESSAGE_ALERT_TYPE; + + break; + } + case START_RESUME_SESSION_ALERT: + { + message = START_RESUME_SESSION_ALERT_STRING; + type = START_RESUME_SESSION_ALERT_TYPE; + + break; + } + case FAILED_RESUME_DISPLAY_ALERT: + { + message = FAILED_RESUME_DISPLAY_ALERT_STRING; + type = FAILED_RESUME_DISPLAY_ALERT_TYPE; + + break; + } + case FAILED_RESUME_DISPLAY_BROKEN_ALERT: + { + message = FAILED_RESUME_DISPLAY_BROKEN_STRING; + type = FAILED_RESUME_DISPLAY_BROKEN_TYPE; + + break; + } + case FAILED_RESUME_VISUALS_ALERT: + { + message = FAILED_RESUME_VISUALS_ALERT_STRING; + type = FAILED_RESUME_VISUALS_ALERT_TYPE; + + break; + } + case FAILED_RESUME_COLORMAPS_ALERT: + { + message = FAILED_RESUME_COLORMAPS_ALERT_STRING; + type = FAILED_RESUME_COLORMAPS_ALERT_TYPE; + + break; + } + case FAILED_RESUME_PIXMAPS_ALERT: + { + message = FAILED_RESUME_PIXMAPS_ALERT_STRING; + type = FAILED_RESUME_PIXMAPS_ALERT_TYPE; + + break; + } + case FAILED_RESUME_DEPTHS_ALERT: + { + message = FAILED_RESUME_DEPTHS_ALERT_STRING; + type = FAILED_RESUME_DEPTHS_ALERT_TYPE; + + break; + } + case FAILED_RESUME_RENDER_ALERT: + { + message = FAILED_RESUME_RENDER_ALERT_STRING; + type = FAILED_RESUME_RENDER_ALERT_TYPE; + + break; + } + case FAILED_RESUME_FONTS_ALERT: + { + message = FAILED_RESUME_FONTS_ALERT_STRING; + type = FAILED_RESUME_FONTS_ALERT_TYPE; + + break; + } + case INTERNAL_ERROR_ALERT: + { + message = INTERNAL_ERROR_ALERT_STRING; + type = INTERNAL_ERROR_ALERT_TYPE; + + break; + } + case ABORT_PROXY_NEGOTIATION_ALERT: + { + message = ABORT_PROXY_NEGOTIATION_ALERT_STRING; + type = ABORT_PROXY_NEGOTIATION_ALERT_TYPE; + + break; + } + case ABORT_PROXY_SHUTDOWN_ALERT: + { + message = ABORT_PROXY_SHUTDOWN_ALERT_STRING; + type = ABORT_PROXY_SHUTDOWN_ALERT_TYPE; + + break; + } + case FAILED_XDMCP_CONNECTION_ALERT: + { + message = FAILED_XDMCP_CONNECTION_ALERT_STRING; + type = FAILED_XDMCP_CONNECTION_ALERT_TYPE; + + break; + } + default: + { + if (lastAlert.code > LAST_PROTO_STEP_7_ALERT) + { + #ifdef WARNING + *logofs << "Loop: WARNING! An unrecognized alert type '" + << lastAlert.code << "' was requested.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": An unrecognized alert type '" + << lastAlert.code << "' was requested.\n"; + } + #ifdef WARNING + else + { + *logofs << "Loop: WARNING! Ignoring obsolete alert type '" + << lastAlert.code << "'.\n" << logofs_flush; + } + #endif + + message = NULL; + type = NULL; + + replace = 0; + + break; + } + } + + if (replace == 1 && IsRunning(lastDialog)) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Killing the previous dialog with pid '" + << lastDialog << "'.\n" << logofs_flush; + #endif + + // + // The client ignores the TERM signal + // on Windows. + // + + #ifdef __CYGWIN32__ + + KillProcess(lastDialog, "dialog", SIGKILL, 0); + + #else + + KillProcess(lastDialog, "dialog", SIGTERM, 0); + + #endif + + SetNotRunning(lastDialog); + + if (proxy != NULL) + { + proxy -> handleResetAlert(); + } + } + + if (message != NULL && type != NULL) + { + lastDialog = NXTransDialog(caption, message, 0, type, local, display); + + if (IsFailed(lastDialog)) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Can't start the NX dialog process.\n" + << logofs_flush; + #endif + + SetNotRunning(lastDialog); + } + #if defined(TEST) || defined(INFO) + else + { + *logofs << "Loop: Dialog started with pid '" + << lastDialog << "'.\n" << logofs_flush; + } + #endif + } + #if defined(TEST) || defined(INFO) + else + { + *logofs << "Loop: No new dialog required for code '" + << lastAlert.code << "'.\n" << logofs_flush; + } + #endif + } + } + + // + // Reset state. + // + + lastAlert.code = 0; + lastAlert.local = 0; +} + +static inline void handleSetAgentInLoop(int &setFDs, fd_set &readSet, + fd_set &writeSet, struct timeval &selectTs) +{ + #ifdef TEST + *logofs << "Loop: Preparing the masks for the agent descriptors.\n" + << logofs_flush; + #endif + + agent -> saveChannelState(); + + agent -> saveReadMask(&readSet); + agent -> saveWriteMask(&writeSet); + + if (control -> ProxyStage >= stage_operational) + { + if (agent -> remoteCanRead(&readSet) || + agent -> remoteCanWrite(&writeSet) || + agent -> localCanRead() || + agent -> proxyCanRead()) + { + #ifdef TEST + *logofs << "Loop: Setting a null timeout with agent descriptors ready.\n" + << logofs_flush; + #endif + + // + // Force a null timeout so we'll bail out + // of the select immediately. We will ac- + // comodate the result code later. + // + + selectTs.tv_sec = 0; + selectTs.tv_usec = 0; + } + } + + #ifdef TEST + *logofs << "Loop: Clearing the read and write agent descriptors.\n" + << logofs_flush; + #endif + + agent -> clearReadMask(&readSet); + agent -> clearWriteMask(&writeSet); +} + +static inline void handleAgentInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, + fd_set &writeSet, struct timeval &selectTs) +{ + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Setting proxy and local agent descriptors.\n" + << logofs_flush; + #endif + + // + // Check if I/O is possible on the local + // agent or the proxy descriptor. + // + + if (resultFDs >= 0) + { + // + // Save if the proxy can read from the + // the agent descriptor. + // + + agent -> saveChannelState(); + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Values were resultFDs " << resultFDs + << " errorFDs " << errorFDs << " setFDs " + << setFDs << ".\n" << logofs_flush; + #endif + + if (agent -> localCanRead() == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Setting agent descriptor FD#" << agent -> + getLocalFd() << " as ready to read.\n" + << logofs_flush; + #endif + + agent -> setLocalRead(&readSet, &resultFDs); + } + + #if defined(TEST) || defined(INFO) + + if (agent -> proxyCanRead(&readSet) == 0 && + agent -> proxyCanRead() == 1) + { + *logofs << "Loop: WARNING! Can read from proxy FD#" + << proxyFD << " but the descriptor " + << "is not selected.\n" << logofs_flush; + } + + if (agent -> proxyCanRead(&readSet) == 1) + { + *logofs << "Loop: Setting proxy descriptor FD#" << agent -> + getProxyFd() << " as ready to read.\n" + << logofs_flush; + } + + #endif + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Values are now resultFDs " << resultFDs + << " errorFDs " << errorFDs << " setFDs " + << setFDs << ".\n" << logofs_flush; + #endif + } +} + +static inline void handleAgentLateInLoop(int &resultFDs, int &errorFDs, int &setFDs, fd_set &readSet, + fd_set &writeSet, struct timeval &selectTs) +{ + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Setting remote agent descriptors.\n" + << logofs_flush; + #endif + + // + // We reset the masks before calling our select. + // We now set the descriptors that are ready but + // only if they were set in the original mask. + // We do this after having executed our loop as + // we may have produced more data and the agent + // descriptors may have become readable or writ- + // able in the meanwhile. + // + + if (resultFDs >= 0) + { + // + // Save if the proxy can read from the + // the agent descriptor. + // + + agent -> saveChannelState(); + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Values were resultFDs " << resultFDs + << " errorFDs " << errorFDs << " setFDs " + << setFDs << ".\n" << logofs_flush; + #endif + + if (agent -> remoteCanRead(agent -> + getSavedReadMask()) == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Setting agent descriptor FD#" << agent -> + getRemoteFd() << " as ready to read.\n" + << logofs_flush; + #endif + + agent -> setRemoteRead(&readSet, &resultFDs); + } + + if (agent -> remoteCanWrite(agent -> + getSavedWriteMask()) == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Setting agent descriptor FD#" << agent -> + getRemoteFd() << " as ready to write.\n" + << logofs_flush; + #endif + + agent -> setRemoteWrite(&writeSet, &resultFDs); + } + + #if defined(TEST) || defined(INFO) + *logofs << "Loop: Values are now resultFDs " << resultFDs + << " errorFDs " << errorFDs << " setFDs " + << setFDs << ".\n" << logofs_flush; + #endif + } +} + +static inline void handleReadableInLoop(int &resultFDs, fd_set &readSet) +{ + if (resultFDs > 0) + { + T_channel_type type = channel_none; + + const char *label = NULL; + int domain = -1; + int fd = -1; + + if (tcpFD != -1 && FD_ISSET(tcpFD, &readSet)) + { + type = channel_x11; + label = "X"; + domain = AF_INET; + fd = tcpFD; + + resultFDs--; + } + + if (unixFD != -1 && FD_ISSET(unixFD, &readSet)) + { + type = channel_x11; + label = "X"; + domain = AF_UNIX; + fd = unixFD; + + resultFDs--; + } + + if (cupsFD != -1 && FD_ISSET(cupsFD, &readSet)) + { + type = channel_cups; + label = "CUPS"; + domain = AF_INET; + fd = cupsFD; + + resultFDs--; + } + + if (auxFD != -1 && FD_ISSET(auxFD, &readSet)) + { + // + // Starting from version 1.5.0 we create real X + // connections for the keyboard channel, so they + // can use the fake authorization cookie. This + // means that there is not such a thing like a + // channel_aux anymore. + // + + type = channel_x11; + label = "auxiliary X11"; + domain = AF_INET; + fd = auxFD; + + resultFDs--; + } + + if (smbFD != -1 && FD_ISSET(smbFD, &readSet)) + { + type = channel_smb; + label = "SMB"; + domain = AF_INET; + fd = smbFD; + + resultFDs--; + } + + if (mediaFD != -1 && FD_ISSET(mediaFD, &readSet)) + { + type = channel_media; + label = "media"; + domain = AF_INET; + fd = mediaFD; + + resultFDs--; + } + + if (httpFD != -1 && FD_ISSET(httpFD, &readSet)) + { + type = channel_http; + label = "HTTP"; + domain = AF_INET; + fd = httpFD; + + resultFDs--; + } + + if (fontFD != -1 && FD_ISSET(fontFD, &readSet)) + { + type = channel_font; + label = "font server"; + domain = AF_INET; + fd = fontFD; + + resultFDs--; + } + + if (slaveFD != -1 && FD_ISSET(slaveFD, &readSet)) + { + type = channel_slave; + label = "slave"; + domain = AF_INET; + fd = slaveFD; + + resultFDs--; + } + + if (type != channel_none) + { + int newFD = AcceptConnection(fd, domain, label); + + if (newFD != -1) + { + if (proxy -> handleNewConnection(type, newFD) < 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Error creating new " << label + << " connection.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Error creating new " << label + << " connection.\n"; + + close(newFD); + + // + // Don't kill the proxy in the case of an error. + // + // HandleCleanup(); + // + } + else if (proxy -> getReadable(newFD) > 0) + { + // + // Add the descriptor, so we can try + // to read immediately. + // + + #ifdef TEST + *logofs << "Loop: Trying to read immediately " + << "from descriptor FD#" << newFD + << ".\n" << logofs_flush; + #endif + + FD_SET(newFD, &readSet); + + resultFDs++; + } + #ifdef TEST + else + { + *logofs << "Loop: Nothing to read immediately " + << "from descriptor FD#" << newFD + << ".\n" << logofs_flush; + } + #endif + } + } + } + + #ifdef DEBUG + *logofs << "Loop: Going to check the readable descriptors.\n" + << logofs_flush; + #endif + + if (proxy -> handleRead(resultFDs, readSet) < 0) + { + #ifdef TEST + *logofs << "Loop: Failure reading from descriptors " + << "for proxy FD#" << proxyFD << ".\n" + << logofs_flush; + #endif + + HandleShutdown(); + } +} + +static inline void handleWritableInLoop(int &resultFDs, fd_set &writeSet) +{ + #ifdef DEBUG + *logofs << "Loop: Going to check the writable descriptors.\n" + << logofs_flush; + #endif + + if (resultFDs > 0 && proxy -> handleFlush(resultFDs, writeSet) < 0) + { + #ifdef TEST + *logofs << "Loop: Failure writing to descriptors " + << "for proxy FD#" << proxyFD << ".\n" + << logofs_flush; + #endif + + HandleShutdown(); + } +} + +static inline void handleFlushInLoop() +{ + #ifdef DEBUG + *logofs << "Loop: Going to flush any data to the proxy.\n" + << logofs_flush; + #endif + + if (agent == NULL || control -> + FlushPolicy == policy_immediate) + { + #if defined(TEST) || defined(INFO) + + if (usePolicy == -1 && control -> + ProxyMode == proxy_client) + { + *logofs << "Loop: WARNING! Flushing the proxy link " + << "on behalf of the agent.\n" << logofs_flush; + } + + #endif + + if (proxy -> handleFlush() < 0) + { + #ifdef TEST + *logofs << "Loop: Failure flushing the proxy FD#" + << proxyFD << ".\n" << logofs_flush; + #endif + + HandleShutdown(); + } + } +} + +static inline void handleRotateInLoop() +{ + #ifdef DEBUG + *logofs << "Loop: Going to rotate channels " + << "for proxy FD#" << proxyFD << ".\n" + << logofs_flush; + #endif + + proxy -> handleRotate(); +} + +static inline void handleEventsInLoop() +{ + #ifdef DEBUG + *logofs << "Loop: Going to check channel events " + << "for proxy FD#" << proxyFD << ".\n" + << logofs_flush; + #endif + + if (proxy -> handleEvents() < 0) + { + #ifdef TEST + *logofs << "Loop: Failure handling channel events " + << "for proxy FD#" << proxyFD << ".\n" + << logofs_flush; + #endif + + HandleShutdown(); + } +} + +static void handleLogReopenInLoop(T_timestamp &logsTs, T_timestamp &nowTs) +{ + // + // If need to limit the size of the + // log file, check the size at each + // loop. + // + + #ifndef QUOTA + + if (diffTimestamp(logsTs, nowTs) > control -> FileSizeCheckTimeout) + + #endif + { + #ifdef DEBUG + *logofs << "Loop: Checking size of log file '" + << errorsFileName << "'.\n" << logofs_flush; + #endif + + #ifndef MIXED + + if (ReopenLogFile(errorsFileName, logofs, control -> FileSizeLimit) < 0) + { + HandleShutdown(); + } + + #endif + + // + // Reset to current timestamp. + // + + logsTs = nowTs; + } +} + +static inline void handleSetReadInLoop(fd_set &readSet, int &setFDs, struct timeval &selectTs) +{ + proxy -> setReadDescriptors(&readSet, setFDs, selectTs); +} + +static inline void handleSetWriteInLoop(fd_set &writeSet, int &setFDs, struct timeval &selectTs) +{ + proxy -> setWriteDescriptors(&writeSet, setFDs, selectTs); +} + +static void handleSetListenersInLoop(fd_set &readSet, int &setFDs) +{ + // + // Set descriptors of listening sockets. + // + + if (control -> ProxyMode == proxy_client) + { + if (useTcpSocket == 1) + { + FD_SET(tcpFD, &readSet); + + if (tcpFD >= setFDs) + { + setFDs = tcpFD + 1; + } + + #ifdef DEBUG + *logofs << "Loop: Selected listener tcpFD " << tcpFD + << " with setFDs " << setFDs << ".\n" + << logofs_flush; + #endif + } + + if (useUnixSocket == 1) + { + FD_SET(unixFD, &readSet); + + if (unixFD >= setFDs) + { + setFDs = unixFD + 1; + } + + #ifdef DEBUG + *logofs << "Loop: Selected listener unixFD " << unixFD + << " with setFDs " << setFDs << ".\n" + << logofs_flush; + #endif + } + + if (useCupsSocket == 1) + { + FD_SET(cupsFD, &readSet); + + if (cupsFD >= setFDs) + { + setFDs = cupsFD + 1; + } + + #ifdef DEBUG + *logofs << "Loop: Selected listener cupsFD " << cupsFD + << " with setFDs " << setFDs << ".\n" + << logofs_flush; + #endif + } + + if (useAuxSocket == 1) + { + FD_SET(auxFD, &readSet); + + if (auxFD >= setFDs) + { + setFDs = auxFD + 1; + } + + #ifdef DEBUG + *logofs << "Loop: Selected listener auxFD " << auxFD + << " with setFDs " << setFDs << ".\n" + << logofs_flush; + #endif + } + + if (useSmbSocket == 1) + { + FD_SET(smbFD, &readSet); + + if (smbFD >= setFDs) + { + setFDs = smbFD + 1; + } + + #ifdef DEBUG + *logofs << "Loop: Selected listener smbFD " << smbFD + << " with setFDs " << setFDs << ".\n" + << logofs_flush; + #endif + } + + if (useMediaSocket == 1) + { + FD_SET(mediaFD, &readSet); + + if (mediaFD >= setFDs) + { + setFDs = mediaFD + 1; + } + + #ifdef DEBUG + *logofs << "Loop: Selected listener mediaFD " << mediaFD + << " with setFDs " << setFDs << ".\n" + << logofs_flush; + #endif + } + + if (useHttpSocket == 1) + { + FD_SET(httpFD, &readSet); + + if (httpFD >= setFDs) + { + setFDs = httpFD + 1; + } + + #ifdef DEBUG + *logofs << "Loop: Selected listener httpFD " << httpFD + << " with setFDs " << setFDs << ".\n" + << logofs_flush; + #endif + } + } + else + { + if (useFontSocket == 1) + { + FD_SET(fontFD, &readSet); + + if (fontFD >= setFDs) + { + setFDs = fontFD + 1; + } + + #ifdef DEBUG + *logofs << "Loop: Selected listener fontFD " << fontFD + << " with setFDs " << setFDs << ".\n" + << logofs_flush; + #endif + } + } + + if (useSlaveSocket == 1) + { + FD_SET(slaveFD, &readSet); + + if (slaveFD >= setFDs) + { + setFDs = slaveFD + 1; + } + + #ifdef DEBUG + *logofs << "Loop: Selected listener slaveFD " << slaveFD + << " with setFDs " << setFDs << ".\n" + << logofs_flush; + #endif + } +} diff --git a/nxcomp/src/MD5.c b/nxcomp/src/MD5.c new file mode 100644 index 000000000..7255ca5c0 --- /dev/null +++ b/nxcomp/src/MD5.c @@ -0,0 +1,403 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "MD5.h" + +#include + +/* + * Try to determine the CPU endianess + * at compile time. + */ + +#if defined(__linux) || defined(__CYGWIN32__) + +#include + +#if (__BYTE_ORDER == __LITTLE_ENDIAN) +#define ARCH_IS_BIG_ENDIAN 0 +#else +#define ARCH_IS_BIG_ENDIAN 1 +#endif + +#endif /* #if defined(__linux) || defined(__CYGWIN32__) */ + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/nxcomp/src/Makefile.am b/nxcomp/src/Makefile.am new file mode 100644 index 000000000..2264cb347 --- /dev/null +++ b/nxcomp/src/Makefile.am @@ -0,0 +1,146 @@ +NULL = + +lib_LTLIBRARIES = libXcomp.la + +libXcomp_la_SOURCES = \ + ActionCache.cpp \ + Agent.cpp \ + Alpha.cpp \ + Auth.cpp \ + Bitmap.cpp \ + BlockCache.cpp \ + BlockCacheSet.cpp \ + ChangeGC.cpp \ + ChangeProperty.cpp \ + ChannelCache.cpp \ + Channel.cpp \ + ChannelEndPoint.cpp \ + CharCache.cpp \ + Children.cpp \ + ClearArea.cpp \ + ClientCache.cpp \ + ClientChannel.cpp \ + ClientProxy.cpp \ + ClientReadBuffer.cpp \ + ClientStore.cpp \ + Colormap.cpp \ + ConfigureWindow.cpp \ + Control.cpp \ + CopyArea.cpp \ + CreateGC.cpp \ + CreatePixmap.cpp \ + DecodeBuffer.cpp \ + EncodeBuffer.cpp \ + FillPoly.cpp \ + Fork.cpp \ + GenericChannel.cpp \ + GenericReadBuffer.cpp \ + GenericReply.cpp \ + GenericRequest.cpp \ + GetImage.cpp \ + GetImageReply.cpp \ + GetProperty.cpp \ + GetPropertyReply.cpp \ + ImageText16.cpp \ + ImageText8.cpp \ + IntCache.cpp \ + InternAtom.cpp \ + Jpeg.cpp \ + Keeper.cpp \ + List.cpp \ + ListFontsReply.cpp \ + Loop.cpp \ + Message.cpp \ + MD5.c \ + Misc.cpp \ + OpcodeStore.cpp \ + Pack.c \ + Pgn.cpp \ + Pipe.cpp \ + PolyArc.cpp \ + PolyFillArc.cpp \ + PolyFillRectangle.cpp \ + PolyLine.cpp \ + PolyPoint.cpp \ + PolySegment.cpp \ + PolyText16.cpp \ + PolyText8.cpp \ + Proxy.cpp \ + ProxyReadBuffer.cpp \ + PutImage.cpp \ + PutPackedImage.cpp \ + QueryFontReply.cpp \ + ReadBuffer.cpp \ + RenderAddGlyphs.cpp \ + RenderChangePicture.cpp \ + RenderComposite.cpp \ + RenderCompositeGlyphs.cpp \ + RenderCreateGlyphSet.cpp \ + RenderCreatePicture.cpp \ + RenderExtension.cpp \ + RenderFillRectangles.cpp \ + RenderFreeGlyphSet.cpp \ + RenderFreePicture.cpp \ + RenderGenericRequest.cpp \ + RenderPictureClip.cpp \ + RenderPictureFilter.cpp \ + RenderPictureTransform.cpp \ + RenderTrapezoids.cpp \ + RenderTriangles.cpp \ + Rgb.cpp \ + Rle.cpp \ + SendEvent.cpp \ + SequenceQueue.cpp \ + ServerCache.cpp \ + ServerChannel.cpp \ + ServerProxy.cpp \ + ServerReadBuffer.cpp \ + ServerStore.cpp \ + SetClipRectangles.cpp \ + SetUnpackAlpha.cpp \ + SetUnpackColormap.cpp \ + SetUnpackGeometry.cpp \ + ShapeExtension.cpp \ + Socket.cpp \ + Split.cpp \ + StaticCompressor.cpp \ + Statistics.cpp \ + Timestamp.cpp \ + TranslateCoords.cpp \ + Transport.cpp \ + Unpack.cpp \ + Vars.c \ + Version.c \ + WriteBuffer.cpp \ + XidCache.cpp \ + Z.cpp \ + $(NULL) + +libXcomp_la_LIBADD = \ + @JPEG_LIBS@ \ + @PNG_LIBS@ \ + @Z_LIBS@ \ + $(NULL) + +AM_CXXFLAGS = \ + $(BASE_CXXFLAGS) \ + $(JPEG_CFLAGS) \ + $(PNG_CFLAGS) \ + $(Z_CFLAGS) \ + $(NULL) + +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + $(NULL) + +libXcomp_la_LDFLAGS = -version-number @LT_COMP_VERSION@ -no-undefined + +libXcompincludedir = $(includedir)/nx +libXcompinclude_HEADERS = \ + $(top_srcdir)/include/MD5.h \ + $(top_srcdir)/include/NX.h \ + $(top_srcdir)/include/NXalert.h \ + $(top_srcdir)/include/NXpack.h \ + $(top_srcdir)/include/NXproto.h \ + $(top_srcdir)/include/NXvars.h \ + $(NULL) diff --git a/nxcomp/src/Message.cpp b/nxcomp/src/Message.cpp new file mode 100644 index 000000000..b75d90c24 --- /dev/null +++ b/nxcomp/src/Message.cpp @@ -0,0 +1,2343 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include + +#include "Misc.h" + +// +// We need channel's cache data. +// + +#include "Message.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. You also +// need to define DUMP in Misc.cpp +// if DUMP is defined here. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Define this to log when messages +// are allocated and deallocated. +// + +#undef REFERENCES + +// +// Keep track of how many bytes are +// occupied by cache. +// + +int MessageStore::totalLocalStorageSize_ = 0; +int MessageStore::totalRemoteStorageSize_ = 0; + +// +// These are used for reference count. +// + +#ifdef REFERENCES + +int Message::references_ = 0; +int MessageStore::references_ = 0; + +#endif + +// +// Here are the methods to handle cached messages. +// + +MessageStore::MessageStore(StaticCompressor *compressor) + + : compressor_(compressor) +{ + // + // Public members. + // + + enableCache = MESSAGE_ENABLE_CACHE; + enableData = MESSAGE_ENABLE_DATA; + enableSplit = MESSAGE_ENABLE_SPLIT; + enableCompress = MESSAGE_ENABLE_COMPRESS; + + dataLimit = MESSAGE_DATA_LIMIT; + dataOffset = MESSAGE_DATA_OFFSET; + + cacheSlots = MESSAGE_CACHE_SLOTS; + cacheThreshold = MESSAGE_CACHE_THRESHOLD; + cacheLowerThreshold = MESSAGE_CACHE_LOWER_THRESHOLD; + + #ifdef TEST + *logofs << "MessageStore: Static compressor is at " + << compressor_ << ".\n" << logofs_flush; + #endif + + md5_state_ = new md5_state_t(); + + #ifdef DEBUG + *logofs << "MessageStore: Created MD5 state for object at " + << this << ".\n" << logofs_flush; + #endif + + lastAdded = cacheSlots; + lastHit = 0; + lastRemoved = 0; + lastRated = nothing; + lastAction = is_discarded; + + // + // Private members. + // + + localStorageSize_ = 0; + remoteStorageSize_ = 0; + + #ifdef TEST + *logofs << "MessageStore: Size of total cache is " + << totalLocalStorageSize_ << " bytes at local side and " + << totalRemoteStorageSize_ << " bytes at remote side.\n" + << logofs_flush; + #endif + + messages_ = new T_messages(); + checksums_ = new T_checksums(); + + temporary_ = NULL; + + #ifdef REFERENCES + + references_++; + + *logofs << "MessageStore: Created new store at " + << this << "out of " << references_ + << " allocated stores.\n" << logofs_flush; + + #endif +} + +MessageStore::~MessageStore() +{ + // + // The virtual destructor of specialized class + // must get rid of both messages in container + // and temporary. + // + + #ifdef DEBUG + *logofs << "MessageStore: Deleting MD5 state for object at " + << this << ".\n" << logofs_flush; + #endif + + delete md5_state_; + + delete messages_; + delete checksums_; + + // + // Update the static members tracking + // size of total memory allocated for + // all stores. + // + + totalLocalStorageSize_ -= localStorageSize_; + totalRemoteStorageSize_ -= remoteStorageSize_; + + #ifdef TEST + *logofs << "MessageStore: Size of total cache is " + << totalLocalStorageSize_ << " bytes at local side and " + << totalRemoteStorageSize_ << " bytes at remote side.\n" + << logofs_flush; + #endif + + #ifdef REFERENCES + + references_--; + + *logofs << "MessageStore: Deleted store at " + << this << " out of " << references_ + << " allocated stores.\n" << logofs_flush; + + #endif +} + +// +// Here are the methods to parse and cache +// messages in the message stores. +// + +int MessageStore::parse(Message *message, int split, const unsigned char *buffer, + unsigned int size, T_checksum_action checksumAction, + T_data_action dataAction, int bigEndian) +{ + // + // Save the message size as received on the link. + // This information will be used to create an ap- + // propriate buffer at the time the message will + // be unparsed. + // + + message -> size_ = size; + message -> i_size_ = identitySize(buffer, size); + message -> c_size_ = 0; + + validateSize(size); + + if (checksumAction == use_checksum) + { + beginChecksum(message); + + parseIdentity(message, buffer, size, bigEndian); + + identityChecksum(message, buffer, size, bigEndian); + + parseData(message, split, buffer, size, checksumAction, dataAction, bigEndian); + + endChecksum(message); + } + else + { + parseIdentity(message, buffer, size, bigEndian); + + parseData(message, split, buffer, size, checksumAction, dataAction, bigEndian); + } + + return 1; +} + +int MessageStore::parse(Message *message, const unsigned char *buffer, + unsigned int size, const unsigned char *compressedData, + const unsigned int compressedDataSize, + T_checksum_action checksumAction, + T_data_action dataAction, int bigEndian) +{ + int offset = identitySize(buffer, size); + + message -> size_ = size; + message -> i_size_ = offset; + message -> c_size_ = compressedDataSize + offset; + + validateSize(message -> size_ - offset, compressedDataSize); + + if (checksumAction == use_checksum) + { + beginChecksum(message); + + parseIdentity(message, buffer, size, bigEndian); + + identityChecksum(message, buffer, size, bigEndian); + + parseData(message, buffer, size, compressedData, compressedDataSize, + checksumAction, dataAction, bigEndian); + + endChecksum(message); + } + else + { + parseIdentity(message, buffer, size, bigEndian); + + parseData(message, buffer, size, compressedData, compressedDataSize, + checksumAction, dataAction, bigEndian); + } + + return 1; +} + +int MessageStore::parseData(Message *message, int split, const unsigned char *buffer, + unsigned int size, T_checksum_action checksumAction, + T_data_action dataAction, int bigEndian) +{ + if ((int) size > message -> i_size_) + { + unsigned int dataSize = size - message -> i_size_; + + if (checksumAction == use_checksum) + { + #ifdef DEBUG + *logofs << name() << ": Calculating checksum of object at " + << message << " with data size " << dataSize + << ".\n" << logofs_flush; + #endif + + dataChecksum(message, buffer, size, bigEndian); + } + + if (dataAction == discard_data) + { + #ifdef DEBUG + *logofs << name() << ": Discarded " << dataSize + << " bytes of plain data. Real size is " + << message -> size_ << " compressed size is " + << message -> c_size_ << ".\n" << logofs_flush; + #endif + + return 1; + } + + // + // Accept anyway data beyond the + // expected limit. + // + + #ifdef TEST + + if (dataSize > (unsigned int) dataLimit) + { + *logofs << name() << ": WARNING! Data is " << dataSize + << " bytes. Ignoring the established limit.\n" + << logofs_flush; + } + + #endif + + if (dataSize != message -> data_.size()) + { + #ifdef DEBUG + *logofs << name() << ": Data will be resized from " + << message -> data_.size() << " to hold a plain buffer of " + << dataSize << " bytes.\n" << logofs_flush; + #endif + + message -> data_.clear(); + + message -> data_.resize(dataSize); + } + + if (split == 0) + { + memcpy(message -> data_.begin(), buffer + message -> i_size_, dataSize); + } + #ifdef TEST + else + { + *logofs << name() << ": Not copied " << dataSize + << " bytes of fake data for the split message.\n" + << logofs_flush; + } + #endif + + #ifdef DEBUG + *logofs << name() << ": Parsed " << dataSize + << " bytes of plain data. Real size is " + << message -> size_ << " compressed size is " + << message -> c_size_ << ".\n" << logofs_flush; + #endif + } + + return 1; +} + +// +// Store the data part in compressed format. +// + +int MessageStore::parseData(Message *message, const unsigned char *buffer, + unsigned int size, const unsigned char *compressedData, + const unsigned int compressedDataSize, + T_checksum_action checksumAction, + T_data_action dataAction, int bigEndian) +{ + if ((int) size > message -> i_size_) + { + unsigned int dataSize = size - message -> i_size_; + + if (checksumAction == use_checksum) + { + #ifdef DEBUG + *logofs << name() << ": Calculating checksum of object at " + << message << " with data size " << dataSize + << ".\n" << logofs_flush; + #endif + + dataChecksum(message, buffer, size, bigEndian); + } + + if (dataAction == discard_data) + { + #ifdef DEBUG + *logofs << name() << ": Discarded " << dataSize + << " bytes of compressed data. Real size is " + << message -> size_ << " compressed size is " + << message -> c_size_ << ".\n" << logofs_flush; + #endif + + return 1; + } + + #ifdef WARNING + if (dataSize > (unsigned int) dataLimit) + { + *logofs << name() << ": WARNING! Data is " << dataSize + << " bytes. Ignoring the established limit!\n" + << logofs_flush; + } + #endif + + dataSize = compressedDataSize; + + if (dataSize != message -> data_.size()) + { + #ifdef DEBUG + *logofs << name() << ": Data will be resized from " + << message -> data_.size() << " to hold a compressed buffer of " + << dataSize << " bytes.\n" << logofs_flush; + #endif + + message -> data_.clear(); + + message -> data_.resize(compressedDataSize); + } + + memcpy(message -> data_.begin(), compressedData, compressedDataSize); + + #ifdef DEBUG + *logofs << name() << ": Parsed " << dataSize + << " bytes of compressed data. Real size is " + << message -> size_ << " compressed size is " + << message -> c_size_ << ".\n" << logofs_flush; + #endif + } + + return 1; +} + +int MessageStore::unparseData(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) +{ + // + // Copy data, if any, to the buffer. + // + + if ((int) size > message -> i_size_) + { + // + // Check if message has been stored + // in compressed format. + // + + if (message -> c_size_ == 0) + { + memcpy(buffer + message -> i_size_, message -> data_.begin(), size - message -> i_size_); + + #ifdef DEBUG + *logofs << name() << ": Unparsed " << message -> size_ - message -> i_size_ + << " bytes of data to a buffer of " << message -> size_ - message -> i_size_ + << ".\n" << logofs_flush; + #endif + } + else + { + #ifdef DEBUG + *logofs << name() << ": Using static compressor at " << (void *) compressor_ + << ".\n" << logofs_flush; + #endif + + if (compressor_ -> + decompressBuffer(buffer + message -> i_size_, + size - message -> i_size_, + message -> data_.begin(), + message -> c_size_ - message -> i_size_) < 0) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Data decompression failed.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Data decompression failed.\n"; + + return -1; + } + + #ifdef DEBUG + *logofs << name() << ": Unparsed " << message -> c_size_ - message -> i_size_ + << " bytes of compressed data to a buffer of " + << message -> size_ - message -> i_size_ << ".\n" << logofs_flush; + #endif + } + } + + // + // We could write size to the buffer but this + // is something the channel class is doing by + // itself. + // + // PutUINT(size >> 2, buffer + 2, bigEndian); + // + + return 1; +} + +void MessageStore::dumpData(const Message *message) const +{ + #ifdef DUMP + + *logofs << name() << ": Dumping enumerated data:\n" << logofs_flush; + + DumpData(message -> data_.begin(), message -> data_.size()); + + #endif + + #ifdef DUMP + + *logofs << name() << ": Dumping checksum data:\n" << logofs_flush; + + DumpData(message -> md5_digest_, MD5_LENGTH); + + #endif +} + +T_checksum MessageStore::getChecksum(const unsigned char *buffer, + unsigned int size, int bigEndian) +{ + Message *message = getTemporary(); + + message -> size_ = size; + message -> i_size_ = identitySize(buffer, size); + message -> c_size_ = 0; + + validateSize(size); + + beginChecksum(message); + + // + // We don't need to extract the identity + // data from the buffer. + // + // parseIdentity(message, buffer, size, bigEndian); + // + + identityChecksum(message, buffer, size, bigEndian); + + parseData(message, 0, buffer, size, use_checksum, discard_data, bigEndian); + + endChecksum(message); + + // + // The caller will have to explicitly + // deallocated the memory after use. + // + + T_checksum checksum = new md5_byte_t[MD5_LENGTH]; + + memcpy(checksum, message -> md5_digest_, MD5_LENGTH); + + return checksum; +} + +int MessageStore::clean(T_checksum_action checksumAction) +{ + int position = lastRemoved + 1; + + if (position >= cacheSlots) + { + position = 0; + } + + #ifdef DEBUG + *logofs << name() << ": Searching a message to remove " + << "starting at position " << position + << " with " << checksums_ -> size() + << " elements in cache.\n" + << logofs_flush; + #endif + + while (position != lastRemoved) + { + #ifdef DEBUG + *logofs << name() << ": Examining position " + << position << ".\n" << logofs_flush; + #endif + + if ((*messages_)[position] != NULL) + { + if (getRating((*messages_)[position], rating_for_clean) == 0) + { + break; + } + else + { + untouch((*messages_)[position]); + } + } + + if (++position == cacheSlots) + { + #ifdef DEBUG + *logofs << name() << ": Rolled position at " + << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + position = 0; + } + } + + // + // If no message is a good candidate, + // then try the object at the next slot + // in respect to last element removed. + // + + if (position == lastRemoved) + { + position = lastRemoved + 1; + + if (position >= cacheSlots) + { + position = 0; + } + + if ((*messages_)[position] == NULL || + (*messages_)[position] -> locks_ != 0) + { + #ifdef DEBUG + *logofs << name() << ": WARNING! No message found " + << "to be actually removed.\n" + << logofs_flush; + #endif + + return nothing; + } + + #ifdef DEBUG + *logofs << name() << ": WARNING! Assuming object " + << "at position " << position << ".\n" + << logofs_flush; + #endif + } + + return position; +} + +// +// This is the insertion method used at local side +// side. Cache at remote side side will be kept in +// sync by telling the to other party where to +// store the message. +// + +int MessageStore::findOrAdd(Message *message, T_checksum_action checksumAction, + T_data_action dataAction, int &added, int &locked) +{ + if (checksumAction != use_checksum) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Internal error in context [A]. " + << "Cannot find or add message to repository " + << "without using checksum.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Internal error in context [A]. " + << "Cannot find or add message to repository " + << "without using checksum.\n"; + + HandleAbort(); + } + + // + // Set added to true only if message + // is inserted in cache. + // + + added = 0; + locked = 0; + + // + // First of all figure out where to + // store this object. + // + + #ifdef DEBUG + *logofs << name() << ": Searching an empty slot " + << "with last rated " << lastRated << " and " + << "last added " << lastAdded << ".\n" + << logofs_flush; + #endif + + int position = lastRated; + + if (position == nothing) + { + position = lastAdded + 1; + + if (position >= cacheSlots) + { + position = 0; + } + + #ifdef DEBUG + *logofs << name() << ": Searching an empty slot " + << "starting at position " << position + << " with " << checksums_ -> size() + << " elements in cache.\n" + << logofs_flush; + #endif + + while (position != lastAdded) + { + #ifdef DEBUG + *logofs << name() << ": Examining position " + << position << ".\n" << logofs_flush; + #endif + + if ((*messages_)[position] == NULL) + { + break; + } + else if (getRating((*messages_)[position], rating_for_insert) == 0) + { + break; + } + else + { + untouch((*messages_)[position]); + } + + if (++position == cacheSlots) + { + #ifdef DEBUG + *logofs << name() << ": Rolled position at " + << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + position = 0; + } + } + } + #ifdef DEBUG + else + { + *logofs << name() << ": Using last rated position " + << position << ".\n" << logofs_flush; + } + #endif + + // + // If we made an extensive check but did not + // find neither a free slot or a message to + // replace, assume slot at next position in + // respect to last added. This can happen if + // all objects in repository have got an hit + // recently. + // + + if (position == lastAdded) + { + position = lastAdded + 1; + + if (position >= cacheSlots) + { + position = 0; + } + + #ifdef DEBUG + *logofs << name() << ": WARNING! Assuming slot " + << "at position " << position << ".\n" + << logofs_flush; + #endif + } + #ifdef DEBUG + else + { + *logofs << name() << ": Found candidate slot " + << "at position " << position << ".\n" + << logofs_flush; + } + #endif + + // + // Save the search result so if the message + // is found in cache, we can use the slot + // at next run. + // + + lastRated = position; + + if ((*messages_)[position] != NULL && + (*messages_)[position] -> locks_ != 0) + { + #ifdef WARNING + *logofs << name() << ": WARNING! Insertion at position " + << position << " would replace a locked message. " + << "Forcing channel to discard the message.\n" + << logofs_flush; + #endif + + #ifdef TEST + *logofs << name() << ": Invalidating rating of object " + << "at position " << position << ".\n" + << logofs_flush; + #endif + + return (lastRated = nothing); + } + + if (checksumAction == use_checksum) + { + T_checksum checksum = getChecksum(message); + + #ifdef TEST + *logofs << name() << ": Searching checksum [" + << DumpChecksum(checksum) << "] in repository.\n" + << logofs_flush; + + #endif + + pair result; + + result = checksums_ -> insert(T_checksums::value_type(checksum, position)); + + // + // Message was found in cache or + // insertion couldn't take place. + // + + if (result.second == 0) + { + if (result.first == checksums_ -> end()) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Failed to insert object " + << "in the cache.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to insert object of type " + << name() << " in the cache.\n"; + + return nothing; + } + + // + // Message is in cache. + // + + #ifdef TEST + *logofs << name() << ": Object is already in cache " + << "at position " << (result.first) -> second + << ".\n" << logofs_flush; + #endif + + #ifdef DEBUG + + printStorageSize(); + + #endif + + // + // Message is locked, probably because + // it has not completely recomposed at + // remote side after a split. + // + + if ((*messages_)[(result.first) -> second] -> locks_ != 0) + { + #ifdef TEST + *logofs << name() << ": WARNING! Object at position " + << (result.first) -> second << " is locked.\n" + << logofs_flush; + #endif + + locked = 1; + } + + // + // Object got a hit, so prevent + // its removal. + // + + if (lastRated == (result.first) -> second) + { + #ifdef TEST + *logofs << name() << ": Resetting rating of object " + << "at position " << (result.first) -> second + << ".\n" << logofs_flush; + #endif + + lastRated = nothing; + } + + return (result.first) -> second; + } + + #ifdef DEBUG + *logofs << name() << ": Could not find message in cache.\n" + << logofs_flush; + #endif + } + + // + // Message not found in hash table (or insertion + // of checksum in hash table was not requested). + // Message was added to cache. + // + + added = 1; + + // + // Log data about the missed message. + // + + #ifdef TEST + + if (opcode() == X_PutImage || opcode() == X_NXPutPackedImage) + { + #ifdef WARNING + *logofs << name() << ": WARNING! Dumping identity of " + << "missed image object of type " << name() + << ".\n" << logofs_flush; + #endif + + dumpIdentity(message); + } + + #endif + + if ((*messages_)[position] != NULL) + { + #ifdef DEBUG + *logofs << name() << ": The message replaces " + << "the old one at position " << position + << ".\n" << logofs_flush; + #endif + + remove(position, checksumAction, dataAction); + } + + (*messages_)[position] = message; + + // + // We used the slot. Perform a new + // search at next run. + // + + lastRated = nothing; + + #ifdef TEST + *logofs << name() << ": Stored message object of size " + << plainSize(position) << " (" << message -> size_ + << "/" << message -> c_size_ << ") at position " + << position << ".\n" << logofs_flush; + #endif + + unsigned int localSize; + unsigned int remoteSize; + + storageSize(message, localSize, remoteSize); + + localStorageSize_ += localSize; + remoteStorageSize_ += remoteSize; + + totalLocalStorageSize_ += localSize; + totalRemoteStorageSize_ += remoteSize; + + #ifdef DEBUG + + printStorageSize(); + + #endif + + // + // Set hits and timestamp at insertion in cache. + // + + message -> hits_ = control -> StoreHitsAddBonus; + message -> last_ = (getTimestamp()).tv_sec; + + message -> locks_ = 0; + + #ifdef DEBUG + *logofs << name() << ": Set last hit of object at " + << strMsTimestamp() << " with a bonus of " + << message -> hits_ << ".\n" << logofs_flush; + #endif + + return position; +} + +// +// Add a parsed message to repository. It is normally used +// at decoding side or at encoding side when we load store +// from disk. To handle messages coming from network, the +// encoding side uses the optimized method findOrAdd(). +// + +int MessageStore::add(Message *message, const int position, + T_checksum_action checksumAction, T_data_action dataAction) +{ + if (position < 0 || position >= cacheSlots) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Cannot add a message " + << "at non existing position " << position + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot add a message " + << "at non existing position " << position + << ".\n"; + + HandleAbort(); + } + + if ((*messages_)[position] != NULL) + { + #ifdef DEBUG + *logofs << name() << ": The message will replace " + << "the old one at position " << position + << ".\n" << logofs_flush; + #endif + + remove(position, checksumAction, dataAction); + } + + #ifdef DEBUG + *logofs << name() << ": Inserting object in repository at position " + << position << ".\n" << logofs_flush; + #endif + + (*messages_)[position] = message; + + // + // Get the object's checksum value + // and insert it in the table. + // + + if (checksumAction == use_checksum) + { + #ifdef DEBUG + *logofs << name() << ": Inserting object's checksum in repository.\n"; + #endif + + T_checksum checksum = getChecksum(message); + + checksums_ -> insert(T_checksums::value_type(checksum, position)); + } + + #ifdef DEBUG + *logofs << name() << ": Stored message object of size " + << plainSize(position) << " (" << message -> size_ + << "/" << message -> c_size_ << ") at position " + << position << ".\n" << logofs_flush; + #endif + + unsigned int localSize; + unsigned int remoteSize; + + storageSize(message, localSize, remoteSize); + + localStorageSize_ += localSize; + remoteStorageSize_ += remoteSize; + + totalLocalStorageSize_ += localSize; + totalRemoteStorageSize_ += remoteSize; + + #ifdef DEBUG + + printStorageSize(); + + #endif + + // + // Set hits and timestamp at insertion in cache. + // + + message -> hits_ = control -> StoreHitsAddBonus; + message -> last_ = (getTimestamp()).tv_sec; + + message -> locks_ = 0; + + #ifdef DEBUG + *logofs << name() << ": Set last hit of object at " + << strMsTimestamp() << " with a bonus of " + << message -> hits_ << ".\n" << logofs_flush; + #endif + + return position; +} + +// +// The following functions don't modify data, +// so they are supposed to be called only at +// the encoding side. +// + +void MessageStore::updateData(const int position, unsigned int dataSize, + unsigned int compressedDataSize) +{ + Message *message = (*messages_)[position]; + + validateSize(dataSize, compressedDataSize); + + if (compressedDataSize != 0) + { + unsigned int localSize; + unsigned int remoteSize; + + storageSize(message, localSize, remoteSize); + + localStorageSize_ -= localSize; + remoteStorageSize_ -= remoteSize; + + totalLocalStorageSize_ -= localSize; + totalRemoteStorageSize_ -= remoteSize; + + message -> c_size_ = compressedDataSize + message -> i_size_; + + #ifdef TEST + + if (message -> size_ != (int) (dataSize + message -> i_size_)) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Size of object looks " + << message -> size_ << " bytes while it " + << "should be " << dataSize + message -> i_size_ + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Size of object looks " + << message -> size_ << " bytes while it " + << "should be " << dataSize + message -> i_size_ + << ".\n"; + + HandleAbort(); + } + + #endif + + storageSize(message, localSize, remoteSize); + + localStorageSize_ += localSize; + remoteStorageSize_ += remoteSize; + + totalLocalStorageSize_ += localSize; + totalRemoteStorageSize_ += remoteSize; + + #ifdef DEBUG + + printStorageSize(); + + #endif + } +} + +void MessageStore::updateData(const T_checksum checksum, unsigned int compressedDataSize) +{ + #ifdef TEST + *logofs << name() << ": Searching checksum [" + << DumpChecksum(checksum) << "] in repository.\n" + << logofs_flush; + #endif + + T_checksums::iterator found = checksums_ -> find(checksum); + + if (found != checksums_ -> end()) + { + Message *message = (*messages_)[found -> second]; + + #ifdef TEST + *logofs << name() << ": Message found in cache at " + << "position " << found -> second << " with size " + << message -> size_ << " and compressed size " + << message -> c_size_ << ".\n" << logofs_flush; + #endif + + updateData(found -> second, message -> size_ - + message -> i_size_, compressedDataSize); + } + #ifdef TEST + else if (checksums_ -> size() > 0) + { + *logofs << name() << ": WARNING! Can't locate the " + << "checksum [" << DumpChecksum(checksum) + << "] for the update.\n" << logofs_flush; + } + #endif +} + +// +// This function replaces the data part of the message +// and updates the information about its size. Split +// messages are advertised to the decoding side with +// their uncompressed size, data is then compressed +// before sending the first chunk. This function is +// called by the decoding side after the split message +// is fully recomposed to replace the dummy data and +// set the real size. +// + +void MessageStore::updateData(const int position, const unsigned char *newData, + unsigned int dataSize, unsigned int compressedDataSize) +{ + Message *message = (*messages_)[position]; + + validateSize(dataSize, compressedDataSize); + + #ifdef TEST + + if (message -> size_ != (int) (dataSize + message -> i_size_)) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Data of object looks " + << dataSize << " bytes while it " << "should be " + << message -> size_ - message -> i_size_ + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Data of object looks " + << dataSize << " bytes while it " << "should be " + << message -> size_ - message -> i_size_ + << ".\n"; + + HandleAbort(); + } + + #endif + + // + // A compressed data size of 0 means that + // message's data was not compressed. + // + + if (compressedDataSize != 0) + { + unsigned int localSize; + unsigned int remoteSize; + + storageSize(message, localSize, remoteSize); + + localStorageSize_ -= localSize; + remoteStorageSize_ -= remoteSize; + + totalLocalStorageSize_ -= localSize; + totalRemoteStorageSize_ -= remoteSize; + + if (message -> c_size_ != (int) compressedDataSize + + message -> i_size_) + { + #ifdef TEST + *logofs << name() << ": Resizing data of message at " + << "position " << position << " from " << message -> + c_size_ << " to " << compressedDataSize + + message -> i_size_ << " bytes.\n" + << logofs_flush; + #endif + + message -> data_.clear(); + + message -> data_.resize(compressedDataSize); + } + + memcpy(message -> data_.begin(), newData, compressedDataSize); + + #ifdef TEST + *logofs << name() << ": Data of message at position " + << position << " has size " << message -> data_.size() + << " and capacity " << message -> data_.capacity() + << ".\n" << logofs_flush; + #endif + + message -> c_size_ = compressedDataSize + message -> i_size_; + + storageSize(message, localSize, remoteSize); + + localStorageSize_ += localSize; + remoteStorageSize_ += remoteSize; + + totalLocalStorageSize_ += localSize; + totalRemoteStorageSize_ += remoteSize; + + #ifdef DEBUG + + printStorageSize(); + + #endif + } + else + { + #ifdef TEST + *logofs << name() << ": No changes to data size for message " + << "at position " << position << ".\n" << logofs_flush; + #endif + + memcpy(message -> data_.begin(), newData, dataSize); + } +} + +int MessageStore::remove(const int position, T_checksum_action checksumAction, + T_data_action dataAction) +{ + Message *message; + + if (position < 0 || position >= cacheSlots || + (message = (*messages_)[position]) == NULL) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Cannot remove " + << "a non existing message at position " + << position << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot remove " + << "a non existing message at position " + << position << ".\n"; + + HandleAbort(); + } + + #if defined(TEST) || defined(INFO) + + if (opcode() == X_PutImage || opcode() == X_NXPutPackedImage) + { + #ifdef WARNING + *logofs << name() << ": WARNING! Discarding image object " + << "of type " << name() << " at position " + << position << ".\n" << logofs_flush; + #endif + } + + #endif + + // + // The checksum is only stored at the encoding + // side. + // + + if (checksumAction == use_checksum) + { + #ifdef DEBUG + *logofs << name() << ": Removing checksum for object at " + << "position " << position << ".\n" << logofs_flush; + #endif + + // + // TODO: If we had stored the iterator and + // not the pointer to the message, we could + // have removed the message without having + // to look up the checksum. + // + + T_checksum checksum = getChecksum(message); + + #ifdef TEST + *logofs << name() << ": Searching checksum [" + << DumpChecksum(checksum) << "] in repository.\n" + << logofs_flush; + #endif + + T_checksums::iterator found = checksums_ -> find(checksum); + + if (found == checksums_ -> end()) + { + #ifdef PANIC + *logofs << name() << ": PANIC! No checksum found for " + << "object at position " << position << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": No checksum found for " + << "object at position " << position << ".\n"; + + HandleAbort(); + } + + #ifdef TEST + + else if (position != found -> second) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Value of position for object " + << "doesn't match position " << position << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Value of position for object " + << "doesn't match position " << position << ".\n"; + + HandleAbort(); + } + + #endif + + checksums_ -> erase(found); + } + + #ifdef DEBUG + *logofs << name() << ": Removing message at position " + << position << " of size " << plainSize(position) + << " (" << message -> size_ << "/" << message -> c_size_ + << ").\n" << logofs_flush; + #endif + + unsigned int localSize; + unsigned int remoteSize; + + storageSize(message, localSize, remoteSize); + + localStorageSize_ -= localSize; + remoteStorageSize_ -= remoteSize; + + totalLocalStorageSize_ -= localSize; + totalRemoteStorageSize_ -= remoteSize; + + recycle(message); + + (*messages_)[position] = NULL; + + #ifdef DEBUG + + printStorageSize(); + + #endif + + return position; +} + +// +// This should only be called at encoding side. +// The decoding side can't rely on the counter +// as it is decremented by the encoding side +// every time the repository is searched for a +// message to be removed. +// + +int MessageStore::getRating(Message *message, T_rating type) const +{ + if (message -> locks_ != 0) + { + #ifdef TEST + *logofs << name() << ": Rate set to -1 as locks of object are " + << (int) message -> locks_ << ".\n" + << logofs_flush; + #endif + + return -1; + } + else if ((type == rating_for_clean || + (int) checksums_ -> size() == cacheSlots) && + message -> hits_ <= control -> StoreHitsLoadBonus) + { + // + // We don't have any free slot or we exceeded the + // available storage size. This is likely to happen + // after having loaded objects from persistent cache. + // It's not a bad idea to discard some messages that + // were restored but never referenced. + // + + #ifdef TEST + + if (type == rating_for_clean) + { + *logofs << name() << ": Rate set to 0 with hits " + << message -> hits_ << " as maximum storage size " + << "was exceeded.\n" << logofs_flush; + } + else + { + *logofs << name() << ": Rate set to 0 with hits " + << message -> hits_ << " as there are no available " + << "slots in store.\n" << logofs_flush; + } + + #endif + + return 0; + } + else if (type == rating_for_clean && + (getTimestamp()).tv_sec - message -> last_ >= + control -> StoreTimeLimit) + { + #ifdef TEST + *logofs << name() << ": Rate set to 0 as last hit of object was " + << (getTimestamp()).tv_sec - message -> last_ + << " seconds ago with limit set to " << control -> + StoreTimeLimit << ".\n" << logofs_flush; + #endif + + return 0; + } + else + { + #ifdef TEST + if (message -> hits_ < 0) + { + *logofs << name() << ": PANIC! Rate of object shouldn't be " + << message -> hits_ << ".\n" << logofs_flush; + + cerr << "Error" << ": Rate of object of type " << name() + << " shouldn't be " << message -> hits_ << ".\n"; + + HandleAbort(); + } + #endif + + #ifdef TEST + *logofs << name() << ": Rate of object is " << message -> hits_ + << " with last hit " << (getTimestamp()).tv_sec - + message -> last_ << " seconds ago.\n" + << logofs_flush; + #endif + + return message -> hits_; + } +} + +int MessageStore::touch(Message *message) const +{ + message -> last_ = (getTimestamp()).tv_sec; + + message -> hits_ += control -> StoreHitsTouch; + + if (message -> hits_ > control -> StoreHitsLimit) + { + message -> hits_ = control -> StoreHitsLimit; + } + + #ifdef TEST + *logofs << name() << ": Increased hits of object to " + << message -> hits_ << " at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + return message -> hits_; +} + +int MessageStore::untouch(Message *message) const +{ + message -> hits_ -= control -> StoreHitsUntouch; + + if (message -> hits_ < 0) + { + message -> hits_ = 0; + } + + #ifdef TEST + *logofs << name() << ": Decreased hits of object to " + << message -> hits_ << ".\n" + << logofs_flush; + #endif + + return message -> hits_; +} + +int MessageStore::lock(const int position) const +{ + Message *message = (*messages_)[position]; + + if (message == NULL) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Can't lock the null " + << "object at position " << position + << ".\n" << logofs_flush; + #endif + + return -1; + } + + #ifdef DEBUG + *logofs << name() << ": Increasing locks of object to " + << (int) message -> locks_ + 1 << ".\n" + << logofs_flush; + #endif + + return ++(message -> locks_); +} + +int MessageStore::unlock(const int position) const +{ + Message *message = (*messages_)[position]; + + if (message == NULL) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Can't unlock the null " + << "object at position " << position + << ".\n" << logofs_flush; + #endif + + return -1; + } + + #ifdef DEBUG + *logofs << name() << ": Decreasing locks of object to " + << (int) message -> locks_ - 1 << ".\n" + << logofs_flush; + #endif + + return --(message -> locks_); +} + +int MessageStore::saveStore(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient, T_checksum_action checksumAction, + T_data_action dataAction, int bigEndian) +{ + Message *message; + + #ifdef TEST + *logofs << name() << ": Opcode of this store is " + << (unsigned int) opcode() << " default size of " + << "identity is " << dataOffset << ".\n" + << logofs_flush; + #endif + + unsigned char *identityBuffer = new unsigned char[dataOffset]; + unsigned char *sizeBuffer = new unsigned char[4 * 2]; + unsigned char *positionBuffer = new unsigned char[4]; + unsigned char *opcodeBuffer = new unsigned char[4]; + + #ifdef DUMP + + char *md5ClientDump = new char[dataOffset * 2 + 128]; + + #endif + + unsigned char value; + + int offset; + + int failed = 0; + + for (int position = 0; position < cacheSlots; position++) + { + message = (*messages_)[position]; + + // + // Don't save split messages. + // + + if (message != NULL && message -> locks_ == 0) + { + // + // Use the total size if offset is + // beyond the real end of message. + // + + offset = dataOffset; + + if (offset > message -> size_) + { + offset = message -> size_; + } + + #ifdef TEST + *logofs << name() << ": Going to save message at position " + << position << ".\n" << logofs_flush; + #endif + + value = 1; + + PutULONG(position, positionBuffer, bigEndian); + PutULONG(opcode(), opcodeBuffer, bigEndian); + + md5_append(md5StateClient, positionBuffer, 4); + md5_append(md5StateClient, opcodeBuffer, 4); + + #ifdef DUMP + + *logofs << "Name=" << name() << logofs_flush; + + sprintf(md5ClientDump," Pos=%d Op=%d\n", position, opcode()); + + *logofs << md5ClientDump << logofs_flush; + + #endif + + if (PutData(cachefs, &value, 1) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure writing " << 1 + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, &value, 1); + + PutULONG(message -> size_, sizeBuffer, bigEndian); + PutULONG(message -> c_size_, sizeBuffer + 4, bigEndian); + + // + // Note that the identity size is not saved with + // the message and will be determined from the + // data read when restoring the identity. + // + + if (PutData(cachefs, sizeBuffer, 4 * 2) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure writing " << 4 * 2 + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, sizeBuffer, 4 * 2); + md5_append(md5StateClient, sizeBuffer, 4 * 2); + + #ifdef DUMP + + sprintf(md5ClientDump, "size = %d c_size = %d\n", + message -> size_, message -> c_size_); + + *logofs << md5ClientDump << logofs_flush; + + #endif + + // + // Prepare a clean buffer for unparse. + // + + CleanData(identityBuffer, offset); + + unparseIdentity(message, identityBuffer, offset, bigEndian); + + if (PutData(cachefs, identityBuffer, offset) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure writing " << offset + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, identityBuffer, offset); + md5_append(md5StateClient, identityBuffer, offset); + + #ifdef DUMP + + for (int i = 0; i < offset; i++) + { + sprintf(md5ClientDump + (i * 2), "%02X", identityBuffer[i]); + } + + *logofs << "Identity = " << md5ClientDump << "\n" << logofs_flush; + + #endif + + // + // Set the real identity size before + // saving the data. + // + + offset = message -> i_size_; + + if (offset > message -> size_) + { + offset = message -> size_; + } + + if (checksumAction == use_checksum) + { + if (PutData(cachefs, message -> md5_digest_, MD5_LENGTH) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure writing " << MD5_LENGTH + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, message -> md5_digest_, MD5_LENGTH); + } + else if (dataAction == use_data) + { + int dataSize = (message -> c_size_ == 0 ? + message -> size_ - offset : + message -> c_size_ - offset); + if (dataSize > 0) + { + if (PutData(cachefs, message -> data_.begin(), dataSize) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure writing " << dataSize + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, message -> data_.begin(), dataSize); + } + } + } + else + { + #ifdef TEST + *logofs << name() << ": Not saving message at position " + << position << ".\n" << logofs_flush; + #endif + + value = 0; + + if (PutData(cachefs, &value, 1) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure writing " << 1 + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, &value, 1); + } + } + + if (failed == 1) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Write to persistent cache file failed.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Write to persistent cache file failed.\n"; + } + + delete [] identityBuffer; + delete [] sizeBuffer; + delete [] positionBuffer; + delete [] opcodeBuffer; + + #ifdef DUMP + + delete [] md5ClientDump; + + #endif + + return (failed == 0 ? 1 : -1); +} + +int MessageStore::loadStore(istream *cachefs, md5_state_t *md5StateStream, + T_checksum_action checksumAction, T_data_action dataAction, + int bigEndian) +{ + Message *message; + + #ifdef TEST + *logofs << name() << ": Opcode of this store is " + << (unsigned int) opcode() << " default size of " + << "identity is " << dataOffset << " slots are " + << cacheSlots << ".\n" << logofs_flush; + #endif + + // + // If packed images or the render extension has been + // disabled we don't need to restore these messages + // in the cache. Encoding of RENDER in 1.4.0 is also + // changed so we want to skip messages saved using + // the old format. We want to restore all the other + // messages so we'll need to skip these one by one. + // + + int skip = 0; + + if ((opcode() == X_NXPutPackedImage && + control -> PersistentCacheLoadPacked == 0) || + (opcode() == X_NXInternalRenderExtension && + control -> PersistentCacheLoadRender == 0)) + { + #ifdef TEST + *logofs << name() << ": All messages for OPCODE#" + << (unsigned int) opcode() << " will be discarded.\n" + << logofs_flush; + #endif + + skip = 1; + } + + unsigned char *identityBuffer = new unsigned char[dataOffset]; + unsigned char *sizeBuffer = new unsigned char[4 * 2]; + + unsigned char value; + + int offset; + + int failed = 0; + + for (int position = 0; position < cacheSlots; position++) + { + if (GetData(cachefs, &value, 1) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure reading " << 1 + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, &value, 1); + + if (value == 1) + { + #ifdef TEST + *logofs << name() << ": Going to load message at position " + << position << ".\n" << logofs_flush; + #endif + + if (GetData(cachefs, sizeBuffer, 4 * 2) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure reading " << 4 * 2 + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, sizeBuffer, 4 * 2); + + message = getTemporary(); + + if (message == NULL) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Can't access temporary storage " + << "for message in context [B].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't access temporary storage " + << "for message in context [B].\n"; + + failed = 1; + + break; + } + + message -> size_ = GetULONG(sizeBuffer, bigEndian); + message -> c_size_ = GetULONG(sizeBuffer + 4, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Size is " << message -> size_ + << " compressed size is " << message -> c_size_ + << ".\n" << logofs_flush; + #endif + + // + // Use the total size if offset is + // beyond the real end of message. + // + + offset = dataOffset; + + if (offset > message -> size_) + { + offset = message -> size_; + } + + if (GetData(cachefs, identityBuffer, offset) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure reading " << offset + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, identityBuffer, offset); + + // + // Get the real identity size based on the value + // reported by the message store. The dataOffset + // value is guaranteed to be greater or equal to + // the maximum identity size of the messages in + // the major store. + // + + offset = identitySize(identityBuffer, offset); + + if (offset > message -> size_) + { + offset = message -> size_; + } + + message -> i_size_ = offset; + + // + // Get identity of message from the buffer we just + // created. Don't calculate neither checksum nor + // data, restore them from stream. Don't pass the + // message's size but the default size of identity. + // + + parseIdentity(message, identityBuffer, offset, bigEndian); + + if (checksumAction == use_checksum) + { + if (message -> md5_digest_ == NULL) + { + message -> md5_digest_ = new md5_byte_t[MD5_LENGTH]; + } + + if (GetData(cachefs, message -> md5_digest_, MD5_LENGTH) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure reading " << MD5_LENGTH + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + // + // Add message's checksum to checksum that will + // be saved together with this cache. Checksum + // will be verified when cache file is restored + // to ensure file is not corrupted. + // + + md5_append(md5StateStream, message -> md5_digest_, MD5_LENGTH); + + if (skip == 1) + { + #ifdef TEST + *logofs << name() << ": Discarding message for OPCODE#" + << (unsigned int) opcode() << ".\n" + << logofs_flush; + #endif + + continue; + } + } + else if (dataAction == use_data) + { + // + // Restore the data part. + // + + int dataSize = (message -> c_size_ == 0 ? + message -> size_ - offset : + message -> c_size_ - offset); + + if (dataSize < 0 || dataSize > control -> MaximumMessageSize) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Bad data size " + << dataSize << " loading persistent cache.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Bad data size " << dataSize + << " loading persistent cache.\n"; + + failed = 1; + + break; + } + else if (dataSize > 0) + { + // + // If need to skip the message let anyway + // it to be part of the calculated MD5. + // + + if (skip == 1) + { + unsigned char *dummy = new unsigned char[dataSize]; + + if (dummy == NULL) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Can't allocate dummy buffer " + << "of size " << dataSize << " loading cache.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate dummy buffer " + << "of size " << dataSize << " loading cache.\n"; + + failed = 1; + + break; + } + + if (GetData(cachefs, dummy, dataSize) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure reading " << dataSize + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + md5_append(md5StateStream, dummy, dataSize); + + delete [] dummy; + + #ifdef TEST + *logofs << name() << ": Discarding message for OPCODE#" + << (unsigned int) opcode() << ".\n" + << logofs_flush; + #endif + + continue; + } + else + { + message -> data_.clear(); + + message -> data_.resize(dataSize); + + if (GetData(cachefs, message -> data_.begin(), dataSize) < 0) + { + #ifdef DEBUG + *logofs << name() << ": PANIC! Failure reading " << dataSize + << " bytes.\n" << logofs_flush; + #endif + + failed = 1; + + break; + } + + // + // Add message's data to cache checksum. + // + + md5_append(md5StateStream, message -> data_.begin(), dataSize); + } + } + else + { + // + // We are here if data part is zero. + // + + if (skip == 1) + { + #ifdef TEST + *logofs << name() << ": Discarding message for OPCODE#" + << (unsigned int) opcode() << ".\n" + << logofs_flush; + #endif + + continue; + } + } + } + + int added; + + added = add(message, position, checksumAction, dataAction); + + if (added != position) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Can't store message " + << "in the cache at position " << position + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't store message " + << "in the cache at position " << position + << ".\n"; + + failed = 1; + + break; + } + else + { + // + // Replace default value of hits set by add + // function. Messages read from cache start + // with a lower bonus than fresh messages + // inserted. + // + + message -> hits_ = control -> StoreHitsLoadBonus; + + #ifdef DEBUG + *logofs << name() << ": Updated last hit of object at " + << strMsTimestamp() << " with a bonus of " + << message -> hits_ << ".\n" << logofs_flush; + #endif + + resetTemporary(); + } + } + else if ((*messages_)[position] != NULL) + { + #ifdef TEST + *logofs << name() << ": Going to remove message at position " + << position << ".\n" << logofs_flush; + #endif + + int removed; + + removed = remove(position, checksumAction, dataAction); + + if (removed != position) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Can't remove message from cache " + << "at position " << position << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't remove message from cache " + << "at position " << position << ".\n"; + + failed = 1; + + break; + } + } + #ifdef TEST + else + { + *logofs << name() << ": Not loading message at position " + << position << ".\n" << logofs_flush; + } + #endif + } + + #ifdef WARNING + + if (failed == 1) + { + *logofs << name() << ": WARNING! Read from persistent cache file failed.\n" + << logofs_flush; + } + + #endif + + delete [] identityBuffer; + delete [] sizeBuffer; + + return (failed == 0 ? 1 : -1); +} + +void MessageStore::storageSize(const Message *message, unsigned int &local, + unsigned int &remote) const +{ + local = remote = storage(); + + // + // Encoding side includes 48 bytes for + // the map of checksums and 24 bytes + // of adjustment for total overhead. + // + + local += MD5_LENGTH + 48 + 24; + + // + // At decoding side we include size of + // data part and 24 bytes of adjustment + // for total overhead. + // + + if (message -> c_size_ == 0) + { + remote += message -> size_ + 24; + } + else + { + remote += message -> c_size_ + 24; + } + + // + // Check if we are the encoding or the + // decoding side and, if needed, swap + // the values. + // + + if (message -> md5_digest_ == NULL) + { + unsigned int t = local; + + local = remote; + + remote = t; + } +} + +void MessageStore::printStorageSize() +{ + #ifdef TEST + + *logofs << name() << ": There are " + << checksums_ -> size() << " checksums in this store " + << "out of " << cacheSlots << " slots.\n" + << logofs_flush; + + *logofs << name() << ": Size of this store is " + << localStorageSize_ << " bytes at local side and " + << remoteStorageSize_ << " bytes at remote side.\n" + << logofs_flush; + + *logofs << name() << ": Size of total cache is " + << totalLocalStorageSize_ << " bytes at local side and " + << totalRemoteStorageSize_ << " bytes at remote side.\n" + << logofs_flush; + + #endif +} diff --git a/nxcomp/src/Message.h b/nxcomp/src/Message.h new file mode 100644 index 000000000..30883f101 --- /dev/null +++ b/nxcomp/src/Message.h @@ -0,0 +1,1089 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Message_H +#define Message_H + +#include + +#include "NXproto.h" + +#include "Misc.h" +#include "Control.h" + +#include "Types.h" +#include "Timestamp.h" + +#include "ActionCache.h" + +#include "StaticCompressor.h" + +// +// Forward class declarations. +// + +class ChannelCache; + +class EncodeBuffer; +class DecodeBuffer; + +class WriteBuffer; + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Define this to know how many messages +// are allocated and deallocated. +// + +#undef REFERENCES + +// +// Set default values. We limit the maximum +// size of a request to 262144 but we need to +// consider the replies, whose size may be up +// to 4MB. +// + +#define MESSAGE_ENABLE_CACHE 0 +#define MESSAGE_ENABLE_DATA 0 +#define MESSAGE_ENABLE_SPLIT 0 +#define MESSAGE_ENABLE_COMPRESS 0 + +#define MESSAGE_DATA_LIMIT 4194304 - 4 +#define MESSAGE_DATA_OFFSET 4 + +#define MESSAGE_CACHE_SLOTS 6000 +#define MESSAGE_CACHE_THRESHOLD 50 +#define MESSAGE_CACHE_LOWER_THRESHOLD 5 + +// +// Base message class. +// + +class Message +{ + friend class MessageStore; + friend class RenderExtensionStore; + + public: + + Message() + { + hits_ = 0; + last_ = 0; + locks_ = 0; + + size_ = 0; + c_size_ = 0; + + md5_digest_ = NULL; + + #ifdef REFERENCES + + references_++; + + *logofs << "Message: Created new message at " + << this << " out of " << references_ + << " allocated messages.\n" + << logofs_flush; + + #endif + } + + Message(const Message &message) + { + size_ = message.size_; + c_size_ = message.c_size_; + i_size_ = message.i_size_; + + hits_ = message.hits_; + last_ = message.last_; + locks_ = message.locks_; + + data_ = message.data_; + + #ifdef REFERENCES + + references_++; + + *logofs << "Message: Creating new copied message at " + << this << " out of " << references_ + << " allocated messages.\n" + << logofs_flush; + #endif + + if (message.md5_digest_ != NULL) + { + md5_digest_ = new md5_byte_t[MD5_LENGTH]; + + memcpy(md5_digest_, message.md5_digest_, MD5_LENGTH); + + #ifdef DEBUG + *logofs << "Message: Created MD5 digest for object at " + << this << ".\n" << logofs_flush; + #endif + } + else + { + md5_digest_ = NULL; + } + } + + ~Message() + { + #ifdef DEBUG + if (md5_digest_ != NULL) + { + *logofs << "Message: Deleted MD5 digest for object at " + << this << ".\n" << logofs_flush; + } + #endif + + delete [] md5_digest_; + + #ifdef REFERENCES + + references_--; + + *logofs << "Message: Deleted message at " + << this << " out of " << references_ + << " allocated messages.\n" + << logofs_flush; + #endif + } + + // + // This is the original message size + // including the data part regardless + // data is still stored in the object. + // + + int size_; + + // + // This is the size of the identity. + // + + int i_size_; + + // + // This is the size, including identity, + // after message has been 'updated' to + // reflect storage of data in compressed + // format. + // + + int c_size_; + + protected: + + // + // This is the data part. + // + + T_data data_; + + // + // Time of last hit. + // + + time_t last_; + + // + // This is the number of cache hits + // registered for the object. + // + + short int hits_; + + // + // This is used to mark messages + // that have been split. + // + + short int locks_; + + // + // This is the MD5 checksum. + // + + md5_byte_t *md5_digest_; + + // + // Keep a reference counter + // of allocated objects. + // + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +// +// Repository of messages. +// + +class MessageStore +{ + public: + + // + // Enable or disable cache of messages in store. + // + + int enableCache; + + // + // Does message have a distinct data part. + // + + int enableData; + + // + // Enable or disable split of data part. + // + + int enableSplit; + + // + // Enable or disable compression of data part. + // + + int enableCompress; + + // + // Set starting point of data part in the message. + // + + int dataOffset; + + // + // Set maximum size for the data part of each message. + // + + int dataLimit; + + // + // Set maximum elements in cache. + // + + int cacheSlots; + + // + // Set the percentage of total cache memory which + // a given type of message is allowed to occupy. + // When threshold is exceeded store is cleaned to + // make room for a new message of the same type. + // + + int cacheThreshold; + + // + // Don't clean the store if percentage of cache + // memory occupied by messages of this type is + // below the threshold. + // + + int cacheLowerThreshold; + + // + // Last operation performed on cache. + // + + T_store_action lastAction; + + // + // Position of last element stored in cache. + // + + short int lastAdded; + + // + // Positions of last element found in cache. + // + + short int lastHit; + + // + // Position of last element erased. + // + + short int lastRemoved; + + // + // Used to encode the the action to + // perform on the store and the slot + // involved. + // + + ActionCache lastActionCache; + + // + // Position in cache where next insertion + // is going to take place. + // + + short int lastRated; + + // + // Constructors and destructors. + // + + public: + + MessageStore(StaticCompressor *compressor = NULL); + + virtual ~MessageStore(); + + virtual const char *name() const = 0; + + virtual unsigned char opcode() const = 0; + + virtual unsigned int storage() const = 0; + + // + // These are members that must be specialized. + // + + public: + + virtual Message *create() const = 0; + + virtual Message *create(const Message &message) const = 0; + + virtual void destroy(Message *message) const = 0; + + void validateSize(int size) + { + if (size < control -> MinimumMessageSize || + size > control -> MaximumMessageSize) + { + *logofs << name() << ": PANIC! Invalid size " << size + << " for message.\n" << logofs_flush; + + cerr << "Error" << ": Invalid size " << size + << " for message opcode " << opcode() << ".\n"; + + HandleAbort(); + } + } + + void validateSize(int dataSize, int compressedDataSize) + { + if (dataSize < 0 || dataSize > control -> + MaximumMessageSize - 4 || compressedDataSize < 0 || + compressedDataSize >= dataSize) + { + *logofs << name() << ": PANIC! Invalid data size " + << dataSize << " and compressed data size " + << compressedDataSize << " for message.\n" + << logofs_flush; + + cerr << "Error" << ": Invalid data size " + << dataSize << " and compressed data size " + << compressedDataSize << " for message " + << "opcode " << (unsigned) opcode() << ".\n"; + + HandleAbort(); + } + } + + // + // Determine if the message can be stored + // in the cache. + // + + virtual int validateMessage(const unsigned char *buffer, int size) + { + return (size >= control -> MinimumMessageSize && + size <= control -> MaximumMessageSize); + } + + // + // Get data offset based on major and minor + // opcode of the message. + // + + virtual int identitySize(const unsigned char *buffer, unsigned int size) + { + return dataOffset; + } + + // + // Encode identity and data using the + // specific message encoding. + // + // Some messages do not implement these + // methods because the encoding is done + // directly in the channel loop. Should + // move the encoding methods in in the + // message classes. + // + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int size, int bigEndian, + ChannelCache *channelCache) const + { + return 1; + } + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const + { + return 1; + } + + // + // Encode differences between message + // in cache and the one to be encoded. + // + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, ChannelCache *channelCache) const + { + } + + // + // Decode differences and update the + // cached version of the same message. + // + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const + { + } + + // + // Post process the message information + // contained in the store by either up- + // dating the size record or the actual + // data part once the message has been + // completely sent to our peer. + // + + void updateData(const int position, unsigned int dataSize, + unsigned int compressedDataSize); + + void updateData(const T_checksum checksum, unsigned int compressedDataSize); + + void updateData(const int position, const unsigned char *newData, + unsigned int dataSize, unsigned int compressedDataSize); + + // + // These members, used internally + // in the message store class, are + // mandatory. + // + + protected: + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const = 0; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const = 0; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const = 0; + + virtual void dumpIdentity(const Message *message) const = 0; + + // + // Design should preserve these from being + // virtual. + // + + int parseData(Message *message, int split, const unsigned char *buffer, + unsigned int size, T_checksum_action checksumAction, + T_data_action dataAction, int bigEndian); + + int parseData(Message *message, const unsigned char *buffer, + unsigned int size, const unsigned char *compressedData, + const unsigned int compressedDataSize, T_checksum_action checksumAction, + T_data_action dataAction, int bigEndian); + + int unparseData(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian); + + // + // Manage efficient allocation of messages + // in the heap. + // + + void recycle(Message *message) + { + #ifdef TEST + + if (message == NULL) + { + *logofs << name() << ": PANIC! Cannot recycle a null message.\n" + << logofs_flush; + + cerr << "Error" << ": Cannot recycle a null message.\n"; + + HandleAbort(); + } + + #endif + + if (temporary_ == NULL) + { + // + // Be careful when reusing the message as + // it can contain valid data that must be + // explicitly deallocated if not needed. + // Note also that you cannot count on the + // initialization made in costructor. + // + + temporary_ = message; + } + else + { + destroy(message); + } + } + + void beginChecksum(Message *message) + { + if (message -> md5_digest_ == NULL) + { + message -> md5_digest_ = new md5_byte_t[MD5_LENGTH]; + + #ifdef DEBUG + *logofs << name() << ": Created MD5 digest structure " + << "for object at " << message << ".\n" + << logofs_flush; + #endif + } + #ifdef DEBUG + else + { + *logofs << name() << ": Using existing MD5 digest structure " + << "for object at " << message << ".\n" + << logofs_flush; + } + #endif + + #ifdef DEBUG + *logofs << name() << ": Prepared MD5 digest for object at " + << message << ".\n" << logofs_flush; + #endif + + md5_init(md5_state_); + } + + void endChecksum(Message *message) + { + md5_finish(md5_state_, message -> md5_digest_); + + #ifdef DEBUG + *logofs << name() << ": Calculated checksum for object at " + << message << ".\n" << logofs_flush; + #endif + } + + void dataChecksum(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) + { + // + // Messages that have a data part starting + // at an offset possibly beyond the end of + // the message, must include the size in + // the identity checksum. + // + + if ((int) size > message -> i_size_) + { + md5_append(md5_state_, buffer + message -> i_size_, + size - message -> i_size_); + } + } + + // + // Repository handling methods. + // + + public: + + // + // Extract identity and data from buffer. + // The size field will be updated at the + // time of data parsing. + // + + int parse(Message *message, int split, const unsigned char *buffer, unsigned int size, + T_checksum_action checksumAction, T_data_action dataAction, int bigEndian); + + int parse(Message *message, const unsigned char *buffer, unsigned int size, + const unsigned char *compressedData, const unsigned int compressedDataSize, + T_checksum_action checksumAction, T_data_action dataAction, int bigEndian); + + // + // From identity and data write the + // final message to the raw buffer. + // + + int unparse(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) + { + return (unparseData(message, buffer, size, bigEndian) && + unparseIdentity(message, buffer, size, bigEndian)); + } + + void dump(const Message *message) const + { + dumpIdentity(message); + + dumpData(message); + } + + void dumpData(const Message *message) const; + + // + // This returns the original message size as it + // was received on the link. It takes in account + // the data part, regardless data is still stored + // in the message object. This information will + // be used at the time message is unparsed. + // + + int plainSize(const int position) const + { + return (*messages_)[position] -> size_; + } + + // + // This returns either the size of identity plus + // the compressed data part or 0 if message is + // stored in uncompressed format. + // + + int compressedSize(const int position) const + { + return (*messages_)[position] -> c_size_; + } + + // + // Returns a pointer to message + // given its position in cache. + // + + Message *get(const int position) const + { + if (position < 0 || position >= cacheSlots) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Requested position " + << position << " is not inside the " + << "container.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Requested position " + << position << " is not inside the" + << "container.\n"; + + HandleAbort(); + } + else if ((*messages_)[position] == NULL) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Message at position " + << position << " is NULL.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Message at position " + << position << " is NULL.\n"; + + HandleAbort(); + } + + return (*messages_)[position]; + } + + // + // This is the method called at encoding + // side to add a message to cache. + // + + int findOrAdd(Message *message, T_checksum_action checksumAction, + T_data_action dataAction, int &added, int &locked); + + // + // Utility interfaces to message insertion + // and deletion. + // + + int add(Message *message, const int position, + T_checksum_action checksumAction, T_data_action dataAction); + + int remove(const int position, T_checksum_action checksumAction, + T_data_action dataAction); + + // + // Make space in the repository by remove + // the first suitable message object. + // + + int clean(T_checksum_action checksumAction); + + // + // Increase or decrease the "rating" of + // the message object. + // + + int touch(Message *message) const; + int untouch(Message *message) const; + + int getTouches(const int position) const + { + Message *message = (*messages_)[position]; + + if (message == NULL) + { + return 0; + } + + return message -> hits_; + } + + // + // Gives a 'weight' to the cached message. A zero + // value means object can be safely removed. A value + // greater than zero means it is advisable to retain + // the object. A negative result means it is mandato- + // ry to keep object in cache. + // + + int getRating(Message *message, T_rating type) const; + + // + // Increase or decrease locks of message at given + // position. A locked message will not be removed + // from the message store until the lock counter + // is zero. + // + + int lock(const int position) const; + int unlock(const int position) const; + + int getLocks(const int position) const + { + Message *message = (*messages_)[position]; + + if (message == NULL) + { + return 0; + } + + return message -> locks_; + } + + T_checksum const getChecksum(const int position) const + { + return getChecksum(get(position)); + } + + T_checksum const getChecksum(const Message *message) const + { + if (message -> md5_digest_ == NULL) + { + #ifdef PANIC + *logofs << name() << ": PANIC! Checksum not initialized " + << "for object at " << message << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Checksum not initialized " + << "for object at " << message << ".\n"; + + HandleAbort(); + } + + #ifdef DEBUG + *logofs << name() << ": Got checksum for object at " + << message << ".\n" << logofs_flush; + #endif + + return message -> md5_digest_; + } + + // + // Calculate the checksum on the fly based the + // opcode in the buffer. Useful in the case a + // message was not processed or was not stored + // in the cache. The returned checksum must be + // explicitly deallocated by the caller, after + // use. + // + + T_checksum getChecksum(const unsigned char *buffer, + unsigned int size, int bigEndian); + + const unsigned char *getData(const Message *message) const + { + return message -> data_.begin(); + } + + int plainSize(const Message *message) const + { + return message -> size_; + } + + int identitySize(Message *message) + { + return message -> i_size_; + } + + int compressedSize(const Message *message) const + { + return message -> c_size_; + } + + Message *getTemporary() + { + if (temporary_ == NULL) + { + temporary_ = create(); + } + + return temporary_; + } + + void resetTemporary() + { + temporary_ = NULL; + } + + // + // On side where we don't have checksums, we + // count how many messages are in the array. + // This is obviously expensive and should be + // only performed when reporting statistics. + // + + int getSize() const + { + int size = checksums_ -> size(); + + if (size == 0) + { + for (int i = 0; i < cacheSlots; i++) + { + if ((*messages_)[i] != NULL) + { + size++; + } + } + } + + return size; + } + + int getLocalStorageSize() const + { + return localStorageSize_; + } + + int getRemoteStorageSize() const + { + return remoteStorageSize_; + } + + int getLocalTotalStorageSize() const + { + return totalLocalStorageSize_; + } + + int getRemoteTotalStorageSize() const + { + return totalRemoteStorageSize_; + } + + static int getCumulativeTotalStorageSize() + { + return (totalLocalStorageSize_ > totalRemoteStorageSize_ ? + totalLocalStorageSize_ : totalRemoteStorageSize_); + } + + int saveStore(ostream *cachefs, md5_state_t *md5_state_stream, + md5_state_t *md5_state_client, T_checksum_action checksumAction, + T_data_action dataAction, int bigEndian); + + int loadStore(istream *cachefs, md5_state_t *md5_state_stream, + T_checksum_action checksumAction, T_data_action dataAction, + int bigEndian); + + protected: + + // + // Estimate the memory requirements of given + // instance of message. Size includes memory + // allocated from heap to store checksum and + // data. + // + + void storageSize(const Message *message, unsigned int &local, + unsigned int &remote) const; + + // + // Just used for debug. + // + + void printStorageSize(); + + // + // Repositories where to save cached messages. + // First is a vector of pointers, the second + // is a hash table used for fast lookups. + // + + T_messages *messages_; + T_checksums *checksums_; + + // + // A message object to be used as a temporary. + // Reuse the temporary object if possible, if + // not, create a new instance. + // + + Message *temporary_; + + // + // Used to calculate message's checksum. + // + + md5_state_t *md5_state_; + + private: + + // + // Used to compress data payload. + // + + StaticCompressor *compressor_; + + // + // Keep track of how many bytes + // are taken by cache. + // + + int localStorageSize_; + int remoteStorageSize_; + + static int totalLocalStorageSize_; + static int totalRemoteStorageSize_; + + // + // Used to track object allocation and deallocation. + // + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +// +// This is an ancillary class of the message +// store, used to encode extensions based on +// the minor opcode. +// + +class MinorMessageStore +{ + public: + + virtual ~MinorMessageStore() + { + } + + virtual const char *name() const = 0; + + virtual int identitySize(const unsigned char *buffer, unsigned int size) = 0; + + virtual int encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const + { + return 1; + } + + virtual int decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, unsigned char type, int bigEndian, + WriteBuffer *writeBuffer, ChannelCache *channelCache) const + { + return 1; + } + + virtual void encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int size, int bigEndian, + ChannelCache *channelCache) const + { + } + + virtual void decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int size, int bigEndian, + ChannelCache *channelCache) const + { + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const = 0; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const = 0; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const + { + } + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const + { + } + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, md5_state_t *md5_state, + int bigEndian) const = 0; +}; + +#endif /* Message_H */ + diff --git a/nxcomp/src/Misc.cpp b/nxcomp/src/Misc.cpp new file mode 100644 index 000000000..b40e6409e --- /dev/null +++ b/nxcomp/src/Misc.cpp @@ -0,0 +1,1934 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "NXproto.h" + +#include "MD5.h" + +#include "Misc.h" +#include "Proxy.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#define OPCODES +#undef TEST +#undef DEBUG + +// +// By default nxproxy binds to all network interfaces, setting +// DEFAULT_LOOPBACK_BIND to 1 enables binding to the loopback +// device only. +// + +const int DEFAULT_LOOPBACK_BIND = 0; + +// +// TCP port offset applied to any NX port specification. +// + +const int DEFAULT_NX_PROXY_PORT_OFFSET = 4000; + +// +// Default TCP port used by client proxy to listen to +// X clients and by server proxy to connect to remote. +// + +const int DEFAULT_NX_PROXY_PORT = 8; + +// +// Default X display number that client proxy imitates. +// + +const int DEFAULT_NX_X_PORT = 8; + +// +// Default ports used for listening for cups, samba, http, +// multimedia and auxiliary X connections. Arbitrary ports +// can be used by passing the service's port at the proxy +// startup. By default ports are determined by adding the +// offset below to the offset of the proxied display. For +// example, if the proxy is impersonating the display :8, +// SMB tunnels can be created by connecting to port 3008. +// +// Considering that the NX server uses to start the first +// session at display offset 1000, we must lower the CUPS +// and SMB ports to avoid interference with normal X ses- +// sions run on the server. +// +// Font server connections are used to let the X server on +// the client connect to a font server on the NX server. +// +// Slave channels can be originated by both sides so we need +// different offsets in the case the user runs both proxies +// on the same host. +// + +const int DEFAULT_NX_CUPS_PORT_OFFSET = 2000; +const int DEFAULT_NX_SMB_PORT_OFFSET = 3000; +const int DEFAULT_NX_MEDIA_PORT_OFFSET = 7000; +const int DEFAULT_NX_AUX_PORT_OFFSET = 8000; +const int DEFAULT_NX_HTTP_PORT_OFFSET = 9000; +const int DEFAULT_NX_FONT_PORT_OFFSET = 10000; + +const int DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET = 11000; +const int DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET = 12000; + +// +// Usage info and copyright. +// + +static const char UsageInfo[] = +"\n\ + Usage: nxproxy [OPTIONS] host:port\n\ +\n\ + -C Specify that nxproxy has to run on the 'X client'\n\ + side, listening for connections and impersonating\n\ + an X server.\n\ +\n\ + -S Specify that nxproxy has to run in 'X server' mode,\n\ + thus forwarding the connections to daemons running\n\ + on the client.\n\ +\n\ + -h Print this message.\n\ +\n\ + -v Print version information.\n\ +\n\ + host:port Put at the end, specifies the host and port of the\n\ + listening proxy.\n\ +\n\ + name=value Set the NX option to the provided value.\n\ +\n\ + Multiple NX options can be specified in the DISPLAY environment\n\ + or on the command line, by using the nx/nx,option=value notation.\n\ +\n\ + Options:\n\ +\n\ + link=s An indication of the link speed that is going to be\n\ + used between the proxies. Usually the compression\n\ + and the other link parameters depend on this setting.\n\ + The value can be either 'modem', 'isdn', 'adsl',\n\ + 'wan', 'lan', 'local' or a bandwidth specification,\n\ + like for example '56k', '1m', '100m', etc.\n\ +\n\ + type=s Type of session, for example 'windows', 'unix-kde'.\n\ + 'unix-application', etc.\n\ +\n\ + display=s Specify the real display where X connections have\n\ + to be forwarded by the proxy running on the client.\n\ +\n\ + listen=n Local port used for accepting the proxy connection.\n\ +\n\ + loopback=b Bind to the loopback device only.\n\ +\n\ + accept=s Name or IP of host that can connect to the proxy.\n\ +\n\ + connect=s Name or IP of host that the proxy will connect to.\n\ +\n\ + port=n Remote port used for the connection.\n\ +\n\ + retry=n Number of connection atempts.\n\ +\n\ + root=s The root directory for the session. Usually is the\n\ + C-* or S-* in the .nx directory in the user's home,\n\ + with '*' being the virtual display.\n\ +\n\ + session=s Name of the session file. The default is the name\n\ + 'session' in the session directory.\n\ +\n\ + errors=s Name of the log file used by the proxy. The default\n\ + is the name 'errors' in the session directory.\n\ +\n\ + stats=s Name of the file where are written the proxy stat-\n\ + istics. The default is a file 'stats' in the session\n\ + directory. The proxy replaces the data in the file\n\ + whenever it receives a SIGUSR1 or SIGUSR2 signal:\n\ +\n\ + SIGUSR1 Gives total statistics, i.e. statistics\n\ + collected since the beginning of the\n\ + session.\n\ +\n\ + SIGUSR2 Gives partial statistics, i.e. statist-\n\ + ics collected since the last time this\n\ + signal was received.\n\ +\n\ + cookie=s Use the provided cookie for authenticating to the\n\ + remote proxy. The same cookie is used as the fake\n\ + value used for the X authorization. The fake cookie\n\ + is replaced on the X server side with the real cookie\n\ + to be used for the display, so that the real cookie\n\ + doesn't have to travel over the net. When not using\n\ + a proxy cookie, any host will be able to connect to\n\ + the proxy. See also the 'accept' parameter.\n\ +\n\ + nodelay=b A boolean indicating if TCP_NODELAY has to be set\n\ + on the proxy link. Old Linux kernels had problems\n\ + with handling TCP_NODELAY on PPP links.\n\ +\n\ + policy=b Let or not the agent decide when it is the best time\n\ + to flush the proxy link. If set to 0, the proxy will\n\ + flush any encoded data immediately. The option has\n\ + only effect on the X client side proxy.\n\ +\n\ + render=b Enable or disable use of the RENDER extension.\n\ +\n\ + taint=b Try to suppress trivial sources of X roundtrips by\n\ + generating the reply on the X client side.\n\ +\n\ + delta=b Enable X differential compression.\n\ +\n\ + data=n Enable or disable the ZLIB data compression. It is\n\ + possible to specify a value between 0 and 9. Usual-\n\ + ly the value is chosen automatically based on the\n\ + requested link setting.\n\ +\n\ + stream=n Enable or disable the ZLIB stream compression. The\n\ + value, between 0 and 9, is usually determined accor-\n\ + ding to the requested link setting.\n\ +\n\ + limit=n Specify a bitrate limit allowed for this session.\n\ +\n\ + memory=n Trigger memory optimizations used to keep small the\n\ + size of X buffers. This is useful on embedded plat-\n\ + forms, or where memory is scarce.\n\ +\n\ + cache=n Size of the in-memory X message cache. Setting the\n\ + value to 0 will disable the memory cache as well\n\ + as the NX differential compression.\n\ +\n\ + images=n Size of the persistent image cache.\n\ +\n\ + shseg=n Enable the use of the MIT-SHM extension between the\n\ + NX client proxy and the real X server. A value greater\n\ + than 1 is assumed to be the size of requested shared\n\ + memory segment. By default, the size of the segment is\n\ + determined based on the size of the in-memory cache.\n\ +\n\ + load=b Enable loading a persistent X message cache at the\n\ + proxy startup.\n\ +\n\ + save=b Enable saving a persistent X message cache at the\n\ + end of session.\n\ +\n\ + cups=n Enable or disable forwarding of CUPS connections,\n\ + by listening on the optional port 'n'.\n\ +\n\ + aux=n Enable or disable forwarding of the auxiliary X chan-\n\ + nel used for controlling the keyboard. The 'keybd=n'\n\ + form is accepted for backward compatibility.\n\ +\n\ + smb=n Enable or disable forwarding of SMB connections. The\n\ + 'samba=n' form is accepted for backward compatibility.\n\ +\n\ + media=n Enable forwarding of audio connections.\n\ +\n\ + http=n Enable forwarding of HTTP connections.\n\ +\n\ + font=n Enable forwarding of reversed connections to a font\n\ + server running on the NX server.\n\ +\n\ + file=n Enable forwarding of file transfer connections.\n\ +\n\ + mask=n Determine the distribution of channel ids between the\n\ + proxies. By default, channels whose ids are multiple\n\ + of 8 (starting from 0) are reserved for the NX client\n\ + side. All the other channels can be allocated by the\n\ + NX server side.\n\ +\n\ + timeout=t Specify the keep-alive timeout used by proxies to\n\ + determine if there is a network problem preventing\n\ + communication with the remote peer. A value of 0\n\ + disables the check.\n\ +\n\ + cleanup=t Specify the number of seconds the proxy has to wait\n\ + at session shutdown before closing all channels.\n\ + The feature is used by the NX server to ensure that\n\ + services are disconnected before shutting down the\n\ + link.\n\ +\n\ + pack=s Determine the method used to compress images.\n\ +\n\ + product=s The product id of the client or server. The value is\n\ + ignored by the proxy, but the client or server can\n\ + provide it to facilitate the support.\n\ +\n\ + core=b Enable production of core dumps when aborting the\n\ + proxy connection.\n\ +\n\ + options=s Specify an additional file containing options that\n\ + has to be merged with option read from the command\n\ + line or the environment.\n\ +\n\ + kill=n Add the given process to the list of daemons that\n\ + must be terminated at session shutdown. Multiple\n\ + 'kill=n' options can be specified. The proxy will\n\ + send them a SIGTERM signal just before exiting.\n\ +\n\ + strict=b Optimize for responsiveness, rather than for the best\n\ + use of all the available bandwidth.\n\ +\n\ + encryption=b Should be set to 1 if the proxy is running as part of\n\ + a program providing encryption of the point to point\n\ + communication.\n\ +\n\ +rootless=b\n\ +geometry=s\n\ +resize=b\n\ +fullscreen=b\n\ +keyboard=s\n\ +clipboard=s\n\ +streaming=n\n\ +backingstore=n\n\ +composite=n\n\ +xinerama=n\n\ +shmem=b\n\ +shpix=b\n\ +kbtype=s\n\ +client=s\n\ +shadow=n\n\ +shadowuid=n\n\ +shadowmode=s\n\ +defer=n\n\ +tile=s\n\ +menu=n\n\ +sleep=n\n\ +tolerancechecks=s\n\ + These options are interpreted by the NX agent. They\n\ + are ignored by the proxy.\n\ +\n\ + Environment:\n\ +\n\ + NX_ROOT The root NX directory is the place where the session\n\ + directory and the cache files are created. This is\n\ + usually overridden by passing the 'root=' option. By\n\ + default, the root NX directory is assumed to be the\n\ + directory '.nx' in the user's home.\n\ +\n\ + NX_SYSTEM The directory where NX programs and libraries reside.\n\ + If not set, the value is assumed to be '/usr/NX'.\n\ + Programs, libraries and data files are respectedly\n\ + searched in the 'bin', 'lib' and 'share' subdirecto-\n\ + ries.\n\ +\n\ + NX_HOME The NX user's home directory. If NX_ROOT is not set\n\ + or invalid, the user's NX directory is created here.\n\ +\n\ + NX_TEMP The directory where the X11 Unix Domain Sockets and\n\ + all temporary files are to be created.\n\ +\n\ + NX_CLIENT The full path to the nxclient executable. If the va-\n\ + riable is not set, the nxclient executable will be\n\ + run assuming that the program is in the system path.\n\ + This can be useful on platforms like Windows and the\n\ + Mac where nxclient is located in a different direct-\n\ + ory compared to the other programs, to make easier\n\ + for the user to execute the program from the shell.\n\ +\n\ + NX_SLAVE_CMD The full path to the slave channel handler. When the\n\ + slave channel is enabled, the agent will listen on a\n\ + port and forward the connection to the NX_SLAVE_CMD\n\ + program. This can be used to implement agent/proxy\n\ + communication for applications such as serial port and\n\ + USB forwarding.\n\ +\n\ + Shell environment:\n\ +\n\ + HOME The variable is checked in the case NX_HOME is not\n\ + set, null or invalid.\n\ +\n\ + TEMP The variable is checked whenever the NX_TEMP direct-\n\ + ory is not set, null or invalid.\n\ +\n\ + PATH The path where all executables are searched, except\n\ + nxclient. If NX_CLIENT is not set, also the client\n\ + executable is searched in the system path.\n\ +\n\ + LD_LIBRARY_PATH\n\ + System-wide library search order. This should be set\n\ + by the program invoking the proxy.\n\ +\n\ + DISPLAY On the X server side, the DISPLAY variable indicates\n\ + the location of the X11 server. When nxcomp is used\n\ + as a transport library, the DISPLAY may represent a\n\ + NX transport specification and options can passed in\n\ + the form nx/nx,option=value...\n\ +\n\ + XAUTHORITY This is the file containing the X11 authorization\n\ + cookie. If not set, the file is assumed to be in\n\ + the user's home (either NX_HOME or HOME).\n\ +\n\ +"; + +const char *GetUsageInfo() +{ + return UsageInfo; +} + +static const char CopyrightInfo[] = +"\ +Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com)\n\ +Copyright (c) 2008-2014 Oleksandr Shneyder \n\ +Copyright (c) 2014-2016 Ulrich Sibiller \n\ +Copyright (c) 2014-2016 Mihai Moldovan \n\ +Copyright (c) 2011-2016 Mike Gabriel \n\ +Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com)\n\ +\n\ +NXCOMP, NX protocol compression and NX extensions to this software\n\ +are copyright of the aforementioned persons and companies.\n\ +\n\ +Redistribution and use of the present software is allowed according\n\ +to terms specified in the file LICENSE.nxcomp which comes in the\n\ +source distribution.\n\ +\n\ +All rights reserved.\n\ +\n\ +NOTE: This software has received contributions from various other\n\ +contributors, only the core maintainers and supporters are listed as\n\ +copyright holders. Please contact us, if you feel you should be listed\n\ +as copyright holder, as well.\n\ +"; + +const char *GetCopyrightInfo() +{ + return CopyrightInfo; +} + +static const char OtherCopyrightInfo[] = +"\ +NX protocol compression is derived from DXPC project.\n\ +\n\ +Copyright (c) 1995,1996 Brian Pane\n\ +Copyright (c) 1996,1997 Zachary Vonler and Brian Pane\n\ +Copyright (c) 1999 Kevin Vigor and Brian Pane\n\ +Copyright (c) 2000,2003 Gian Filippo Pinzari and Brian Pane\n\ +\n\ +All rights reserved.\n\ +"; + +const char *GetOtherCopyrightInfo() +{ + return OtherCopyrightInfo; +} + +int _hostBigEndian = 0; +int _storeBigEndian = 0; + +const unsigned int IntMask[33] = +{ + 0x00000000, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, + 0xffffffff +}; + +unsigned int GetUINT(unsigned const char *buffer, int bigEndian) +{ + // + // It doesn't work on SPARCs if the buffer + // is not aligned to the word boundary. We + // should check the CPU, not the OS as this + // surely applies to other architectures. + // + + #ifndef __sun + + if (_hostBigEndian == bigEndian) + { + return *((unsigned short *) buffer); + } + + #else + + if (_hostBigEndian == bigEndian && ((unsigned int) buffer) & 0x1 == 0) + { + return *((unsigned short *) buffer); + } + + #endif + + unsigned int result; + + if (bigEndian) + { + result = *buffer; + + result <<= 8; + + result += buffer[1]; + } + else + { + result = buffer[1]; + + result <<= 8; + + result += *buffer; + } + + return result; +} + +unsigned int GetULONG(unsigned const char *buffer, int bigEndian) +{ + // + // It doesn't work on SPARCs if the buffer + // is not aligned to word the boundary. + // + + #ifndef __sun + + if (_hostBigEndian == bigEndian) + { + return *((unsigned int *) buffer); + } + + #else + + if (_hostBigEndian == bigEndian && ((unsigned int) buffer) & 0x3 == 0) + { + return *((unsigned int *) buffer); + } + + #endif + + const unsigned char *next = (bigEndian ? buffer : buffer + 3); + + unsigned int result = 0; + + for (int i = 0; i < 4; i++) + { + result <<= 8; + + result += *next; + + if (bigEndian) + { + next++; + } + else + { + next--; + } + } + + return result; +} + +void PutUINT(unsigned int value, unsigned char *buffer, int bigEndian) +{ + if (_hostBigEndian == bigEndian) + { + *((unsigned short *) buffer) = value; + + return; + } + + if (bigEndian) + { + buffer[1] = (unsigned char) (value & 0xff); + + value >>= 8; + + *buffer = (unsigned char) value; + } + else + { + *buffer = (unsigned char) (value & 0xff); + + value >>= 8; + + buffer[1] = (unsigned char) value; + } +} + +void PutULONG(unsigned int value, unsigned char *buffer, int bigEndian) +{ + if (_hostBigEndian == bigEndian) + { + *((unsigned int *) buffer) = value; + + return; + } + + if (bigEndian) + { + buffer += 3; + + for (int i = 4; i > 0; i--) + { + *buffer-- = (unsigned char) (value & 0xff); + + value >>= 8; + } + } + else + { + for (int i = 4; i > 0; i--) + { + *buffer++ = (unsigned char) (value & 0xff); + + value >>= 8; + } + } +} + +int CheckData(istream *fs) +{ + if (fs == NULL || fs -> fail()) + { + return -1; + } + + return 1; +} + +int CheckData(ostream *fs) +{ + if (fs == NULL || fs -> fail()) + { + return -1; + } + + return 1; +} + +int PutData(ostream *fs, const unsigned char *buffer, int size) +{ + fs -> write((char *) buffer, size); + + #ifdef DEBUG + *logofs << "PutData: Written " << size << " bytes with eof " + << fs -> eof() << " fail " << fs -> fail() << " and bad " + << fs -> bad() << ".\n" << logofs_flush; + #endif + + if (fs -> fail()) + { + return -1; + } + + return size; +} + +int GetData(istream *fs, unsigned char *buffer, int size) +{ + fs -> read((char *) buffer, size); + + #ifdef DEBUG + *logofs << "GetData: Read " << size << " bytes with eof " + << fs -> eof() << " fail " << fs -> fail() + << " and bad " << fs -> bad() << ".\n" + << logofs_flush; + #endif + + #ifdef __APPLE__ + + if (fs -> bad()) + { + return -1; + } + + #else + + if (fs -> fail()) + { + return -1; + } + + #endif + + return size; +} + +int FlushData(ostream *fs) +{ + fs -> flush(); + + if (fs -> fail()) + { + return -1; + } + + return 1; +} + +unsigned int RoundUp2(unsigned int x) +{ + unsigned int y = x / 2; + + y *= 2; + + if (y != x) + { + y += 2; + } + + return y; +} + +unsigned int RoundUp4(unsigned int x) +{ + unsigned int y = x / 4; + + y *= 4; + + if (y != x) + { + y += 4; + } + + return y; +} + +unsigned int RoundUp8(unsigned int x) +{ + unsigned int y = x / 8; + + y *= 8; + + if (y != x) + { + y += 8; + } + + return y; +} + +const char *DumpSignal(int signal) +{ + switch (signal) + { + case SIGCHLD: + { + return "SIGCHLD"; + } + case SIGUSR1: + { + return "SIGUSR1"; + } + case SIGUSR2: + { + return "SIGUSR2"; + } + case SIGHUP: + { + return "SIGHUP"; + } + case SIGINT: + { + return "SIGINT"; + } + case SIGTERM: + { + return "SIGTERM"; + } + case SIGPIPE: + { + return "SIGPIPE"; + } + case SIGALRM: + { + return "SIGALRM"; + } + case SIGVTALRM: + { + return "SIGVTALRM"; + } + case SIGWINCH: + { + return "SIGWINCH"; + } + case SIGIO: + { + return "SIGIO"; + } + case SIGTSTP: + { + return "SIGTSTP"; + } + case SIGTTIN: + { + return "SIGTTIN"; + } + case SIGTTOU: + { + return "SIGTTOU"; + } + case SIGSEGV: + { + return "SIGSEGV"; + } + case SIGABRT: + { + return "SIGABRT"; + } + default: + { + return "Unknown"; + } + } +} + +const char *DumpPolicy(int type) +{ + switch ((T_flush_policy) type) + { + case policy_immediate: + { + return "immediate"; + } + case policy_deferred: + { + return "deferred"; + } + default: + { + #ifdef PANIC + *logofs << "Misc: PANIC! Unknown policy type '" + << type << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unknown policy type '" + << type << "'.\n"; + + HandleCleanup(); + } + } +} + +const char *DumpAction(int type) +{ + T_store_action action = (T_store_action) type; + + if (action == IS_HIT) + { + return "is_hit"; + } + else if (action == IS_ADDED) + { + return "is_added"; + } + else if (action == is_discarded) + { + return "is_discarded"; + } + else if (action == is_removed) + { + return "is_removed"; + } + else + { + #ifdef PANIC + *logofs << "Misc: PANIC! Unknown store action '" + << type << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unknown store action '" + << type << "'.\n"; + + HandleCleanup(); + } +} + +const char *DumpState(int type) +{ + switch ((T_split_state) type) + { + case split_added: + { + return "split_added"; + } + case split_missed: + { + return "split_missed"; + } + case split_loaded: + { + return "split_loaded"; + } + case split_aborted: + { + return "split_aborted"; + } + case split_notified: + { + return "split_notified"; + } + default: + { + #ifdef PANIC + *logofs << "Misc: PANIC! Unknown split state '" + << type << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unknown split state '" + << type << "'.\n"; + + HandleCleanup(); + } + } +} + +const char *DumpControl(int code) +{ + switch ((T_proxy_code) code) + { + case code_new_x_connection: + { + return "code_new_x_connection"; + } + case code_new_cups_connection: + { + return "code_new_cups_connection"; + } + case code_new_aux_connection: + { + return "code_new_aux_connection"; + } + case code_new_smb_connection: + { + return "code_new_smb_connection"; + } + case code_new_media_connection: + { + return "code_new_media_connection"; + } + case code_switch_connection: + { + return "code_switch_connection"; + } + case code_drop_connection: + { + return "code_drop_connection"; + } + case code_finish_connection: + { + return "code_finish_connection"; + } + case code_begin_congestion: + { + return "code_begin_congestion"; + } + case code_end_congestion: + { + return "code_end_congestion"; + } + case code_alert_request: + { + return "code_alert_request"; + } + case code_alert_reply: + { + return "code_alert_reply"; + } + case code_reset_request: + { + return "code_reset_request"; + } + case code_reset_reply: + { + return "code_reset_reply"; + } + case code_load_request: + { + return "code_load_request"; + } + case code_load_reply: + { + return "code_load_reply"; + } + case code_save_request: + { + return "code_save_request"; + } + case code_save_reply: + { + return "code_save_reply"; + } + case code_shutdown_request: + { + return "code_shutdown_request"; + } + case code_shutdown_reply: + { + return "code_shutdown_reply"; + } + case code_control_token_request: + { + return "code_control_token_request"; + } + case code_control_token_reply: + { + return "code_control_token_reply"; + } + case code_configuration_request: + { + return "code_configuration_request"; + } + case code_configuration_reply: + { + return "code_configuration_reply"; + } + case code_statistics_request: + { + return "code_statistics_request"; + } + case code_statistics_reply: + { + return "code_statistics_reply"; + } + case code_new_http_connection: + { + return "code_new_http_connection"; + } + case code_sync_request: + { + return "code_sync_request"; + } + case code_sync_reply: + { + return "code_sync_reply"; + } + case code_new_font_connection: + { + return "code_new_font_connection"; + } + case code_new_slave_connection: + { + return "code_new_slave_connection"; + } + case code_finish_listeners: + { + return "code_finish_listeners"; + } + case code_split_token_request: + { + return "code_split_token_request"; + } + case code_split_token_reply: + { + return "code_split_token_reply"; + } + case code_data_token_request: + { + return "code_data_token_request"; + } + case code_data_token_reply: + { + return "code_data_token_reply"; + } + default: + { + #ifdef WARNING + *logofs << "Misc: WARNING! Unknown control code '" + << code << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Unknown control code '" + << code << "'.\n"; + + return "unknown"; + } + } +} + +const char *DumpSession(int code) +{ + switch ((T_session_mode) code) + { + case session_agent: + { + return "session_agent"; + } + case session_shadow: + { + return "session_shadow"; + } + case session_proxy: + { + return "session_proxy"; + } + default: + { + #ifdef WARNING + *logofs << "Misc: WARNING! Unknown session type '" + << code << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Unknown session type '" + << code << "'.\n"; + + return "unknown"; + } + } +} + +const char *DumpToken(int type) +{ + switch ((T_token_type) type) + { + case token_control: + { + return "token_control"; + } + case token_split: + { + return "token_split"; + } + case token_data: + { + return "token_data"; + } + default: + { + #ifdef WARNING + *logofs << "Misc: WARNING! Unknown token type '" + << type << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Unknown token type '" + << type << "'.\n"; + + return "unknown"; + } + } +} + +// +// Always include this in code as it is generally +// needed to test channels and split store. +// + +const char *DumpChecksum(const void *checksum) +{ + static char string[MD5_LENGTH * 2 + 1]; + + if (checksum != NULL) + { + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + sprintf(string + (i * 2), "%02X", ((unsigned char *) checksum)[i]); + } + } + else + { + strcpy(string, "null"); + } + + return string; +} + +// +// Define OPCODES here and in the channel +// if you want to log the opcode literal. +// + +#ifdef OPCODES + +const char *DumpOpcode(const int &opcode) +{ + switch (opcode) + { + case X_CreateWindow: + { + return "X_CreateWindow"; + } + case X_ChangeWindowAttributes: + { + return "X_ChangeWindowAttributes"; + } + case X_GetWindowAttributes: + { + return "X_GetWindowAttributes"; + } + case X_DestroyWindow: + { + return "X_DestroyWindow"; + } + case X_DestroySubwindows: + { + return "X_DestroySubwindows"; + } + case X_ChangeSaveSet: + { + return "X_ChangeSaveSet"; + } + case X_ReparentWindow: + { + return "X_ReparentWindow"; + } + case X_MapWindow: + { + return "X_MapWindow"; + } + case X_MapSubwindows: + { + return "X_MapSubwindows"; + } + case X_UnmapWindow: + { + return "X_UnmapWindow"; + } + case X_UnmapSubwindows: + { + return "X_UnmapSubwindows"; + } + case X_ConfigureWindow: + { + return "X_ConfigureWindow"; + } + case X_CirculateWindow: + { + return "X_CirculateWindow"; + } + case X_GetGeometry: + { + return "X_GetGeometry"; + } + case X_QueryTree: + { + return "X_QueryTree"; + } + case X_InternAtom: + { + return "X_InternAtom"; + } + case X_GetAtomName: + { + return "X_GetAtomName"; + } + case X_ChangeProperty: + { + return "X_ChangeProperty"; + } + case X_DeleteProperty: + { + return "X_DeleteProperty"; + } + case X_GetProperty: + { + return "X_GetProperty"; + } + case X_ListProperties: + { + return "X_ListProperties"; + } + case X_SetSelectionOwner: + { + return "X_SetSelectionOwner"; + } + case X_GetSelectionOwner: + { + return "X_GetSelectionOwner"; + } + case X_ConvertSelection: + { + return "X_ConvertSelection"; + } + case X_SendEvent: + { + return "X_SendEvent"; + } + case X_GrabPointer: + { + return "X_GrabPointer"; + } + case X_UngrabPointer: + { + return "X_UngrabPointer"; + } + case X_GrabButton: + { + return "X_GrabButton"; + } + case X_UngrabButton: + { + return "X_UngrabButton"; + } + case X_ChangeActivePointerGrab: + { + return "X_ChangeActivePointerGrab"; + } + case X_GrabKeyboard: + { + return "X_GrabKeyboard"; + } + case X_UngrabKeyboard: + { + return "X_UngrabKeyboard"; + } + case X_GrabKey: + { + return "X_GrabKey"; + } + case X_UngrabKey: + { + return "X_UngrabKey"; + } + case X_AllowEvents: + { + return "X_AllowEvents"; + } + case X_GrabServer: + { + return "X_GrabServer"; + } + case X_UngrabServer: + { + return "X_UngrabServer"; + } + case X_QueryPointer: + { + return "X_QueryPointer"; + } + case X_GetMotionEvents: + { + return "X_GetMotionEvents"; + } + case X_TranslateCoords: + { + return "X_TranslateCoords"; + } + case X_WarpPointer: + { + return "X_WarpPointer"; + } + case X_SetInputFocus: + { + return "X_SetInputFocus"; + } + case X_GetInputFocus: + { + return "X_GetInputFocus"; + } + case X_QueryKeymap: + { + return "X_QueryKeymap"; + } + case X_OpenFont: + { + return "X_OpenFont"; + } + case X_CloseFont: + { + return "X_CloseFont"; + } + case X_QueryFont: + { + return "X_QueryFont"; + } + case X_QueryTextExtents: + { + return "X_QueryTextExtents"; + } + case X_ListFonts: + { + return "X_ListFonts"; + } + case X_ListFontsWithInfo: + { + return "X_ListFontsWithInfo"; + } + case X_SetFontPath: + { + return "X_SetFontPath"; + } + case X_GetFontPath: + { + return "X_GetFontPath"; + } + case X_CreatePixmap: + { + return "X_CreatePixmap"; + } + case X_FreePixmap: + { + return "X_FreePixmap"; + } + case X_CreateGC: + { + return "X_CreateGC"; + } + case X_ChangeGC: + { + return "X_ChangeGC"; + } + case X_CopyGC: + { + return "X_CopyGC"; + } + case X_SetDashes: + { + return "X_SetDashes"; + } + case X_SetClipRectangles: + { + return "X_SetClipRectangles"; + } + case X_FreeGC: + { + return "X_FreeGC"; + } + case X_ClearArea: + { + return "X_ClearArea"; + } + case X_CopyArea: + { + return "X_CopyArea"; + } + case X_CopyPlane: + { + return "X_CopyPlane"; + } + case X_PolyPoint: + { + return "X_PolyPoint"; + } + case X_PolyLine: + { + return "X_PolyLine"; + } + case X_PolySegment: + { + return "X_PolySegment"; + } + case X_PolyRectangle: + { + return "X_PolyRectangle"; + } + case X_PolyArc: + { + return "X_PolyArc"; + } + case X_FillPoly: + { + return "X_FillPoly"; + } + case X_PolyFillRectangle: + { + return "X_PolyFillRectangle"; + } + case X_PolyFillArc: + { + return "X_PolyFillArc"; + } + case X_PutImage: + { + return "X_PutImage"; + } + case X_GetImage: + { + return "X_GetImage"; + } + case X_PolyText8: + { + return "X_PolyText8"; + } + case X_PolyText16: + { + return "X_PolyText16"; + } + case X_ImageText8: + { + return "X_ImageText8"; + } + case X_ImageText16: + { + return "X_ImageText16"; + } + case X_CreateColormap: + { + return "X_CreateColormap"; + } + case X_FreeColormap: + { + return "X_FreeColormap"; + } + case X_CopyColormapAndFree: + { + return "X_CopyColormapAndFree"; + } + case X_InstallColormap: + { + return "X_InstallColormap"; + } + case X_UninstallColormap: + { + return "X_UninstallColormap"; + } + case X_ListInstalledColormaps: + { + return "X_ListInstalledColormaps"; + } + case X_AllocColor: + { + return "X_AllocColor"; + } + case X_AllocNamedColor: + { + return "X_AllocNamedColor"; + } + case X_AllocColorCells: + { + return "X_AllocColorCells"; + } + case X_AllocColorPlanes: + { + return "X_AllocColorPlanes"; + } + case X_FreeColors: + { + return "X_FreeColors"; + } + case X_StoreColors: + { + return "X_StoreColors"; + } + case X_StoreNamedColor: + { + return "X_StoreNamedColor"; + } + case X_QueryColors: + { + return "X_QueryColors"; + } + case X_LookupColor: + { + return "X_LookupColor"; + } + case X_CreateCursor: + { + return "X_CreateCursor"; + } + case X_CreateGlyphCursor: + { + return "X_CreateGlyphCursor"; + } + case X_FreeCursor: + { + return "X_FreeCursor"; + } + case X_RecolorCursor: + { + return "X_RecolorCursor"; + } + case X_QueryBestSize: + { + return "X_QueryBestSize"; + } + case X_QueryExtension: + { + return "X_QueryExtension"; + } + case X_ListExtensions: + { + return "X_ListExtensions"; + } + case X_ChangeKeyboardMapping: + { + return "X_ChangeKeyboardMapping"; + } + case X_GetKeyboardMapping: + { + return "X_GetKeyboardMapping"; + } + case X_ChangeKeyboardControl: + { + return "X_ChangeKeyboardControl"; + } + case X_GetKeyboardControl: + { + return "X_GetKeyboardControl"; + } + case X_Bell: + { + return "X_Bell"; + } + case X_ChangePointerControl: + { + return "X_ChangePointerControl"; + } + case X_GetPointerControl: + { + return "X_GetPointerControl"; + } + case X_SetScreenSaver: + { + return "X_SetScreenSaver"; + } + case X_GetScreenSaver: + { + return "X_GetScreenSaver"; + } + case X_ChangeHosts: + { + return "X_ChangeHosts"; + } + case X_ListHosts: + { + return "X_ListHosts"; + } + case X_SetAccessControl: + { + return "X_SetAccessControl"; + } + case X_SetCloseDownMode: + { + return "X_SetCloseDownMode"; + } + case X_KillClient: + { + return "X_KillClient"; + } + case X_RotateProperties: + { + return "X_RotateProperties"; + } + case X_ForceScreenSaver: + { + return "X_ForceScreenSaver"; + } + case X_SetPointerMapping: + { + return "X_SetPointerMapping"; + } + case X_GetPointerMapping: + { + return "X_GetPointerMapping"; + } + case X_SetModifierMapping: + { + return "X_SetModifierMapping"; + } + case X_GetModifierMapping: + { + return "X_GetModifierMapping"; + } + case X_NoOperation: + { + return "X_NoOperation"; + } + case X_NXInternalGenericData: + { + return "X_NXInternalGenericData"; + } + // + // case X_NXInternalGenericReply: + // { + // return "X_NXInternalGenericReply"; + // } + // + case X_NXInternalGenericRequest: + { + return "X_NXInternalGenericRequest"; + } + case X_NXInternalShapeExtension: + { + return "X_NXInternalShapeExtension"; + } + case X_NXGetControlParameters: + { + return "X_NXGetControlParameters"; + } + case X_NXGetCleanupParameters: + { + return "X_NXGetCleanupParameters"; + } + case X_NXGetImageParameters: + { + return "X_NXGetImageParameters"; + } + case X_NXGetUnpackParameters: + { + return "X_NXGetUnpackParameters"; + } + case X_NXGetShmemParameters: + { + return "X_NXGetShmemParameters"; + } + case X_NXGetFontParameters: + { + return "X_NXGetFontParameters"; + } + case X_NXSetExposeParameters: + { + return "X_NXSetExposeParameters"; + } + case X_NXSetCacheParameters: + { + return "X_NXSetCacheParameters"; + } + case X_NXStartSplit: + { + return "X_NXStartSplit"; + } + case X_NXEndSplit: + { + return "X_NXEndSplit"; + } + case X_NXSplitData: + { + return "X_NXSplitData"; + } + case X_NXSplitEvent: + { + return "X_NXSplitEvent"; + } + case X_NXCommitSplit: + { + return "X_NXCommitSplit"; + } + case X_NXFinishSplit: + { + return "X_NXFinishSplit"; + } + case X_NXAbortSplit: + { + return "X_NXAbortSplit"; + } + case X_NXFreeSplit: + { + return "X_NXFreeSplit"; + } + case X_NXSetUnpackGeometry: + { + return "X_NXSetUnpackGeometry"; + } + case X_NXSetUnpackColormap: + { + return "X_NXSetUnpackColormap"; + } + case X_NXSetUnpackAlpha: + { + return "X_NXSetUnpackAlpha"; + } + case X_NXPutPackedImage: + { + return "X_NXPutPackedImage"; + } + case X_NXFreeUnpack: + { + return "X_NXFreeUnpack"; + } + default: + { + if (opcode > 127) + { + return "Extension"; + } + else + { + return "?"; + } + } + } +} + +#else /* #ifdef OPCODES */ + +const char *DumpOpcode(const int &opcode) +{ + return "?"; +} + +#endif /* #ifdef OPCODES */ + +void DumpData(const unsigned char *buffer, unsigned int size) +{ + if (buffer != NULL) + { + unsigned int i = 0; + + while (i < size) + { + *logofs << "[" << i << "]\t"; + + for (unsigned int ii = 0; i < size && ii < 8; i++, ii++) + { + *logofs << (unsigned int) (buffer[i]) << "\t"; + } + + *logofs << "\n" << logofs_flush; + } + } +} + +void DumpChecksum(const unsigned char *buffer, unsigned int size) +{ + if (buffer != NULL) + { + md5_byte_t md5_digest[MD5_LENGTH]; + + md5_state_t md5_state; + + md5_init(&md5_state); + + md5_append(&md5_state, buffer, size); + + md5_finish(&md5_state, md5_digest); + + char md5_string[MD5_LENGTH * 2 + 1]; + + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + sprintf(md5_string + (i * 2), "%02X", md5_digest[i]); + } + + *logofs << "[" << md5_string << "]" << logofs_flush; + } +} + +void DumpBlockChecksums(const unsigned char *buffer, + unsigned int size, unsigned int block) +{ + for (unsigned int i = 0; i < (size / block); i++) + { + *logofs << "[" << i * block << "]"; + + DumpChecksum(buffer + (i * block), block); + + *logofs << "\n"; + } + + if (size % block > 0) + { + *logofs << "[" << size / block * block << "]"; + + DumpChecksum(buffer + (size / block * block), size % block); + + *logofs << "\n"; + } +} + +void DumpHexData(const unsigned char *buffer, unsigned int size) +{ + char message [65536]; + char ascii [17]; + + unsigned int index = 0; + unsigned int linescan = 0; + unsigned int index_ascii = 0; + + sprintf (message,"\n#### Start Dump Buffer of [%.5d] Bytes ####\n\n",size); + + *logofs << message << logofs_flush; + + // + // "Index 0 1 2 3 4 5 6 7 8 9 a b c d e f Ascii " + // "----- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ----------------" + // "00000 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................" + // + + sprintf (message,"Index 0 1 2 3 4 5 6 7 8 9 a b c d e f Ascii \n"); + *logofs << message << logofs_flush; + sprintf (message,"----- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ----------------\n"); + *logofs << message << logofs_flush; + + index = 0; + + while (index < size) + { + memset (ascii, ' ', sizeof(ascii)); + + ascii[16] = '\0'; + + sprintf (message,"%.5d ", index); + + for (index_ascii = 0, linescan = index; + ((index < (linescan + 16)) && (index < size)); + index++, index_ascii++) + { + if (isprint(buffer [index])) + { + ascii[index_ascii] = buffer [index]; + } + else + { + ascii[index_ascii] = '.'; + } + + sprintf (&message [strlen (message)],"%.2x ", (unsigned char) buffer [index]); + } + + for (linescan = index_ascii; linescan < 16; linescan++) + { + strcat (&message [strlen (message)], " "); + } + + sprintf (&message [strlen (message)]," %s\n", ascii); + + *logofs << message << logofs_flush; + } + + sprintf (message,"\n#### End Dump Buffer ####\n\n"); + + *logofs << message << logofs_flush; +} diff --git a/nxcomp/src/Misc.h b/nxcomp/src/Misc.h new file mode 100644 index 000000000..997630137 --- /dev/null +++ b/nxcomp/src/Misc.h @@ -0,0 +1,279 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Misc_H +#define Misc_H + +#include +#include + +#include +#include + +#ifdef __sun + +#include + +#endif + +using namespace std; + +// +// This is MD5 length. +// + +#define MD5_LENGTH 16 + +// +// Error handling macros. +// + +#define ESET(e) (errno = (e)) +#define EGET() (errno) +#define ESTR() strerror(errno) + +// +// TCP port offset applied to NX port specification. +// + +extern const int DEFAULT_NX_PROXY_PORT_OFFSET; + +// +// Default TCP port used by client proxy to listen +// to X clients and by server proxy to connect to +// remote. +// + +extern const int DEFAULT_NX_PROXY_PORT; + +// +// Default X display number that client +// proxy imitates. +// + +extern const int DEFAULT_NX_X_PORT; + +// +// Establish the port offsets for the additional +// services. +// + +extern const int DEFAULT_NX_CUPS_PORT_OFFSET; +extern const int DEFAULT_NX_SMB_PORT_OFFSET; +extern const int DEFAULT_NX_MEDIA_PORT_OFFSET; +extern const int DEFAULT_NX_AUX_PORT_OFFSET; +extern const int DEFAULT_NX_HTTP_PORT_OFFSET; +extern const int DEFAULT_NX_FONT_PORT_OFFSET; + +// +// Slave channels can be originated by both sides +// so they need to have different port offsets +// in the case the user runs both proxies on the +// same host. +// + +extern const int DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET; +extern const int DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET; + +// +// NX proxy binds to all network interfaces by default +// With the -loopback parameter, you can switch +// over to binding to the loopback device only. +// + +extern const int DEFAULT_LOOPBACK_BIND; + +// +// Return strings containing various info. +// + +const char *GetUsageInfo(); +const char *GetCopyrightInfo(); +const char *GetOtherCopyrightInfo(); + +// +// Define this if you want immediate flush of +// the log output. +// + +#define FLUSH_LOGOFS + +// +// Global objects providing shared functions. +// + +class Auth; +class Control; +class Statistics; + +extern Auth *auth; +extern Control *control; +extern Statistics *statistics; + +// +// Log file. +// + +extern ostream *logofs; + +// +// Cleanup code. +// + +void HandleAbort() __attribute__((noreturn)); +void HandleShutdown() __attribute__((noreturn)); + +extern "C" +{ + void HandleCleanup(int code = 0) __attribute__((noreturn)); + void HandleCleanupForReconnect(); +} + +// +// Manage signal handlers. +// + +void DisableSignals(); +void EnableSignals(); + +// +// Manage timers. +// + +void SetTimer(int value); +void ResetTimer(); + +// +// Show a dialog asking the user if he/she +// wants to close the current session. Look +// in the alerts file for the known critical +// events. +// + +void HandleAlert(int code, int local); + +// +// Run the callback registered by the proxy +// or the agent. +// + +void KeeperCallback(); +void FlushCallback(int length); + +// +// Return the string literal corresponding +// the value. +// + +const char *DumpSignal(int signal); +const char *DumpPolicy(int type); +const char *DumpControl(int code); +const char *DumpSession(int code); +const char *DumpAction(int type); +const char *DumpState(int type); +const char *DumpToken(int type); + +// +// Print out content of buffer to log file. +// You need to define DUMP or OPCODES in +// the source to have these compiled. +// + +const char *DumpOpcode(const int &opcode); +const char *DumpChecksum(const void *checksum); + +void DumpData(const unsigned char *data, unsigned int length); +void DumpHexData(const unsigned char *data, unsigned int length); +void DumpChecksum(const unsigned char *data, unsigned int length); +void DumpBlockChecksums(const unsigned char *data, unsigned int length, + unsigned int block); + +// +// Defines logofs_flush as an empty string to +// avoid calling the corresponding ostream's +// flush() function. +// + +#ifdef FLUSH_LOGOFS + +#define logofs_flush "" ; logofs -> flush() + +#else + +#define logofs_flush "" + +#endif + +// +// Is the host where local proxy is running +// big-endian? +// + +extern int _hostBigEndian; +extern int _storeBigEndian; + +inline void setHostBigEndian(int flag) +{ + _hostBigEndian = flag; +} + +inline int hostBigEndian() +{ + return _hostBigEndian; +} + +inline int storeBigEndian() +{ + return _storeBigEndian; +} + +extern const unsigned int IntMask[33]; + +unsigned int GetUINT(unsigned const char *buffer, int bigEndian); +unsigned int GetULONG(unsigned const char *buffer, int bigEndian); +void PutUINT(unsigned int value, unsigned char *buffer, int bigEndian); +void PutULONG(unsigned int value, unsigned char *buffer, int bigEndian); + +inline void CleanData(unsigned char *buffer, int size) +{ + unsigned char *end = buffer + size; + + while (buffer < end) + { + *buffer++ = 0x00; + } +} + +int CheckData(istream *fs); +int CheckData(ostream *fs); +int PutData(ostream *fs, const unsigned char *buffer, int size); +int GetData(istream *fs, unsigned char *buffer, int size); +int FlushData(ostream *fs); + +unsigned int RoundUp2(unsigned int x); +unsigned int RoundUp4(unsigned int x); +unsigned int RoundUp8(unsigned int x); + +#endif /* Misc_H */ diff --git a/nxcomp/src/NXmitshm.h b/nxcomp/src/NXmitshm.h new file mode 100644 index 000000000..939d488fb --- /dev/null +++ b/nxcomp/src/NXmitshm.h @@ -0,0 +1,56 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef NXmitshm_H +#define NXmitshm_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Import opcodes from + * to get rid of weird dependencies from other + * headers of X environment. + */ + +#define X_ShmQueryVersion 0 +#define X_ShmAttach 1 +#define X_ShmDetach 2 +#define X_ShmPutImage 3 +#define X_ShmGetImage 4 +#define X_ShmCreatePixmap 5 + +#define ShmCompletion 0 +#define ShmNumberEvents (ShmCompletion + 1) + +#define BadShmSeg 0 +#define ShmNumberErrors (BadShmSeg + 1) + +#ifdef __cplusplus +} +#endif + +#endif /* NXmitshm_H */ diff --git a/nxcomp/src/NXrender.h b/nxcomp/src/NXrender.h new file mode 100644 index 000000000..280715833 --- /dev/null +++ b/nxcomp/src/NXrender.h @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef NXrender_H +#define NXrender_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Import this from + * to compile under old XFree86 distributions + * when render extension was not present yet. + */ + +#define X_RenderQueryVersion 0 +#define X_RenderQueryPictFormats 1 +#define X_RenderQueryPictIndexValues 2 +#define X_RenderQueryDithers 3 +#define X_RenderCreatePicture 4 +#define X_RenderChangePicture 5 +#define X_RenderSetPictureClipRectangles 6 +#define X_RenderFreePicture 7 +#define X_RenderComposite 8 +#define X_RenderScale 9 +#define X_RenderTrapezoids 10 +#define X_RenderTriangles 11 +#define X_RenderTriStrip 12 +#define X_RenderTriFan 13 +#define X_RenderColorTrapezoids 14 +#define X_RenderColorTriangles 15 +#define X_RenderTransform 16 +#define X_RenderCreateGlyphSet 17 +#define X_RenderReferenceGlyphSet 18 +#define X_RenderFreeGlyphSet 19 +#define X_RenderAddGlyphs 20 +#define X_RenderAddGlyphsFromPicture 21 +#define X_RenderFreeGlyphs 22 +#define X_RenderCompositeGlyphs8 23 +#define X_RenderCompositeGlyphs16 24 +#define X_RenderCompositeGlyphs32 25 +#define X_RenderFillRectangles 26 +/* 0.5 */ +#define X_RenderCreateCursor 27 +/* 0.6 */ +#define X_RenderSetPictureTransform 28 +#define X_RenderQueryFilters 29 +#define X_RenderSetPictureFilter 30 +#define X_RenderCreateAnimCursor 31 + +#ifdef __cplusplus +} +#endif + +#endif /* NXrender_H */ diff --git a/nxcomp/src/OpcodeCache.h b/nxcomp/src/OpcodeCache.h new file mode 100644 index 000000000..e07a1b997 --- /dev/null +++ b/nxcomp/src/OpcodeCache.h @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef OpcodeCache_H +#define OpcodeCache_H + +#include "CharCache.h" + +class OpcodeCache +{ + friend class EncodeBuffer; + friend class DecodeBuffer; + + public: + + OpcodeCache() + { + slot_ = 0; + } + + ~OpcodeCache() + { + } + + private: + + CharCache base_[256]; + unsigned char slot_; +}; + +#endif /* OpcodeCache_H */ diff --git a/nxcomp/src/OpcodeStore.cpp b/nxcomp/src/OpcodeStore.cpp new file mode 100644 index 000000000..21b919c8a --- /dev/null +++ b/nxcomp/src/OpcodeStore.cpp @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "OpcodeStore.h" + +OpcodeStore::OpcodeStore() +{ + // + // Assign values of the specific + // NX opcodes. + // + + getControlParameters = X_NXGetControlParameters; + getCleanupParameters = X_NXGetCleanupParameters; + getImageParameters = X_NXGetImageParameters; + getUnpackParameters = X_NXGetUnpackParameters; + getShmemParameters = X_NXGetShmemParameters; + getFontParameters = X_NXGetFontParameters; + + startSplit = X_NXStartSplit; + endSplit = X_NXEndSplit; + commitSplit = X_NXCommitSplit; + finishSplit = X_NXFinishSplit; + abortSplit = X_NXAbortSplit; + + splitData = X_NXSplitData; + splitEvent = X_NXSplitEvent; + + setCacheParameters = X_NXSetCacheParameters; + setExposeParameters = X_NXSetExposeParameters; + + setUnpackGeometry = X_NXSetUnpackGeometry; + setUnpackColormap = X_NXSetUnpackColormap; + setUnpackAlpha = X_NXSetUnpackAlpha; + + putPackedImage = X_NXPutPackedImage; + + freeUnpack = X_NXFreeUnpack; + freeSplit = X_NXFreeSplit; + + // + // These values must be fetched + // from the X server. + // + + shapeExtension = 0; + renderExtension = 0; + + // + // Events sent as ClientMessage. + // + + noSplitNotify = NXNoSplitNotify; + startSplitNotify = NXStartSplitNotify; + commitSplitNotify = NXCommitSplitNotify; + endSplitNotify = NXEndSplitNotify; + emptySplitNotify = NXEmptySplitNotify; +} + +OpcodeStore::~OpcodeStore() +{ +} diff --git a/nxcomp/src/OpcodeStore.h b/nxcomp/src/OpcodeStore.h new file mode 100644 index 000000000..d041ed4b8 --- /dev/null +++ b/nxcomp/src/OpcodeStore.h @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef OpcodeStore_H +#define OpcodeStore_H + +#include "NXproto.h" + +class OpcodeStore +{ + public: + + OpcodeStore(); + + ~OpcodeStore(); + + // + // Map NX protocol messages. At the moment mapping is hard- + // coded. Opcodes should be instead agreed with the proxied + // X server (by excluding all opcodes used for extensions) + // and exported by the proxy class to channels. + // + // Some toolkits query the server only once for extensions' + // opcodes and share the same settings across all channels. + // This could be a problem as channels needed to monitor the + // traffic to find out the extensions' opcodes themselves, + // so it is important that proxy passes an instance of this + // class to new channels. + // + + unsigned char getControlParameters; + unsigned char getCleanupParameters; + unsigned char getImageParameters; + unsigned char getUnpackParameters; + unsigned char getShmemParameters; + unsigned char getFontParameters; + + unsigned char startSplit; + unsigned char endSplit; + unsigned char commitSplit; + unsigned char finishSplit; + unsigned char abortSplit; + + unsigned char splitData; + unsigned char splitEvent; + + unsigned char setCacheParameters; + unsigned char setExposeParameters; + + unsigned char setUnpackGeometry; + unsigned char setUnpackColormap; + unsigned char setUnpackAlpha; + + unsigned char putPackedImage; + + unsigned char freeUnpack; + unsigned char freeSplit; + + unsigned char shapeExtension; + unsigned char renderExtension; + + unsigned char noSplitNotify; + unsigned char startSplitNotify; + unsigned char commitSplitNotify; + unsigned char endSplitNotify; + unsigned char emptySplitNotify; +}; + +#endif /* OpcodeStore_H */ diff --git a/nxcomp/src/Pack.c b/nxcomp/src/Pack.c new file mode 100644 index 000000000..97fb93b5f --- /dev/null +++ b/nxcomp/src/Pack.c @@ -0,0 +1,180 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "NXpack.h" + +const ColorMask Mask8TrueColor = { 128, 63, 240, 7 }; +const ColorMask Mask64TrueColor = { 192, 7, 240, 4 }; +const ColorMask Mask256TrueColor = { 255, 0, 255, 0 }; +const ColorMask Mask512TrueColor = { 224, 5, 240, 4 }; +const ColorMask Mask4KTrueColor = { 240, 4, 240, 2 }; +const ColorMask Mask32KTrueColor = { 248, 3, 248, 2 }; +const ColorMask Mask64KTrueColor = { 255, 0, 255, 0 }; +const ColorMask Mask256KTrueColor = { 252, 1, 252, 1 }; +const ColorMask Mask2MTrueColor = { 255, 0, 254, 1 }; +const ColorMask Mask16MTrueColor = { 255, 0, 255, 0 }; + +const ColorMask *MethodColorMask(unsigned int method) +{ + switch (method) + { + case MASK_8_COLORS: + { + return &Mask8TrueColor; + } + case MASK_64_COLORS: + { + return &Mask64TrueColor; + } + case MASK_256_COLORS: + { + return &Mask256TrueColor; + } + case MASK_512_COLORS: + { + return &Mask512TrueColor; + } + case MASK_4K_COLORS: + { + return &Mask4KTrueColor; + } + case MASK_32K_COLORS: + { + return &Mask32KTrueColor; + } + case MASK_64K_COLORS: + { + return &Mask64KTrueColor; + } + case MASK_256K_COLORS: + { + return &Mask256KTrueColor; + } + case MASK_2M_COLORS: + { + return &Mask2MTrueColor; + } + case MASK_16M_COLORS: + { + return &Mask16MTrueColor; + } + default: + { + return NULL; + } + } +} + +int MethodBitsPerPixel(unsigned int method) +{ + switch (method) + { + case PACK_MASKED_8_COLORS: + case PACK_JPEG_8_COLORS: + case PACK_PNG_8_COLORS: + { + return 8; + } + case PACK_MASKED_64_COLORS: + case PACK_JPEG_64_COLORS: + case PACK_PNG_64_COLORS: + { + return 8; + } + case PACK_MASKED_256_COLORS: + case PACK_JPEG_256_COLORS: + case PACK_PNG_256_COLORS: + { + return 8; + } + case PACK_MASKED_512_COLORS: + case PACK_JPEG_512_COLORS: + case PACK_PNG_512_COLORS: + { + return 16; + } + case PACK_MASKED_4K_COLORS: + case PACK_JPEG_4K_COLORS: + case PACK_PNG_4K_COLORS: + { + return 16; + } + case PACK_MASKED_32K_COLORS: + case PACK_JPEG_32K_COLORS: + case PACK_PNG_32K_COLORS: + { + return 16; + } + case PACK_MASKED_64K_COLORS: + case PACK_JPEG_64K_COLORS: + case PACK_PNG_64K_COLORS: + { + return 16; + } + case PACK_MASKED_256K_COLORS: + case PACK_JPEG_256K_COLORS: + case PACK_PNG_256K_COLORS: + { + return 24; + } + case PACK_MASKED_2M_COLORS: + case PACK_JPEG_2M_COLORS: + case PACK_PNG_2M_COLORS: + { + return 24; + } + case PACK_MASKED_16M_COLORS: + case PACK_JPEG_16M_COLORS: + case PACK_PNG_16M_COLORS: + { + return 24; + } + case PACK_BITMAP_16M_COLORS: + case PACK_RGB_16M_COLORS: + case PACK_RLE_16M_COLORS: + { + return 24; + } + default: + { + return 0; + } + } +} + +#ifdef __cplusplus +} +#endif diff --git a/nxcomp/src/Pgn.cpp b/nxcomp/src/Pgn.cpp new file mode 100644 index 000000000..649227f52 --- /dev/null +++ b/nxcomp/src/Pgn.cpp @@ -0,0 +1,809 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// This file obviously supports PNG +// decompression. It was renamed to +// avoid name clashes on Windows. +// + +#include + +#ifdef ANDROID +#include +#endif +#include +#include +#include + +#include "Unpack.h" +#include "Pgn.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define RGB24_TO_PIXEL(bpp,r,g,b) \ + ((((CARD##bpp)(r) & 0xFF) * srcRedMax2 + 127) / 255 \ + << srcRedShift2 | \ + (((CARD##bpp)(g) & 0xFF) * srcGreenMax2 + 127) / 255 \ + << srcGreenShift2 | \ + (((CARD##bpp)(b) & 0xFF) * srcBlueMax2 + 127) / 255 \ + << srcBlueShift2) + +#define RGB24_TO_PIXEL32(r,g,b) \ + (((CARD32)(r) & 0xFF) << srcRedShift2 | \ + ((CARD32)(g) & 0xFF) << srcGreenShift2 | \ + ((CARD32)(b) & 0xFF) << srcBlueShift2) + +// +// Functions from Unpack.cpp +// + +extern int Unpack32To32(const T_colormask *colormask, const unsigned int *data, + unsigned int *out, unsigned int *end); + +extern int Unpack24To24(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +extern int Unpack16To16(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +// +// Local functions used for the png decompression. +// + +static int DecompressPng16(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, + int byteOrder); + +static int DecompressPng24(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, + int byteOrder); + +static int DecompressPng32(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, + int byteOrder); + +static void PngReadData(png_structp png_ptr, png_bytep data, png_size_t length); + +// +// Colormap stuff. +// + +CARD16 srcRedMax2, srcGreenMax2, srcBlueMax2; +CARD8 srcRedShift2, srcGreenShift2, srcBlueShift2; + +// +// Attributes used for the png decompression. +// + +static char *tmpBuf; +static int tmpBufSize = 0; +static int streamPos; + +int UnpackPng(T_geometry *geometry, unsigned char method, unsigned char *srcData, + int srcSize, int dstBpp, int dstWidth, int dstHeight, + unsigned char *dstData, int dstSize) +{ + int byteOrder = geometry -> image_byte_order; + + // + // Check if data is coming from a failed unsplit. + // + + if (srcSize < 2 || (srcData[0] == SPLIT_PATTERN && + srcData[1] == SPLIT_PATTERN)) + { + #ifdef WARNING + *logofs << "UnpackPng: WARNING! Skipping unpack of dummy data.\n" + << logofs_flush; + #endif + + return -1; + } + + #ifdef DEBUG + *logofs << "UnpackPng: Decompressing image with " + << "srcSize " << srcSize << " and bpp " + << dstBpp << ".\n" << logofs_flush; + #endif + + srcRedShift2 = ffs(geometry -> red_mask) - 1; + srcGreenShift2 = ffs(geometry -> green_mask) - 1; + srcBlueShift2 = ffs(geometry -> blue_mask) - 1; + srcRedMax2 = geometry -> red_mask >> srcRedShift2; + srcGreenMax2 = geometry -> green_mask >> srcGreenShift2; + srcBlueMax2 = geometry -> blue_mask >> srcBlueShift2; + + // + // Make enough space in the temporary + // buffer to have one complete row of + // the image with 3 bytes per pixel. + // + + tmpBufSize = dstWidth * 3; + tmpBuf = new char [tmpBufSize]; + + if (tmpBuf == NULL) + { + #ifdef PANIC + *logofs << "UnpackPng: PANIC! Cannot allocate " + << dstWidth * 3 << " bytes for PNG " + << "decompressed data.\n" << logofs_flush; + #endif + + delete [] tmpBuf; + + return -1; + } + + int result = 1; + + switch (dstBpp) + { + case 8: + { + // + // Simply move the data from srcData to dstData + // taking into consideration the correct padding. + // + + int row; + + unsigned char * dstBuff = dstData; + unsigned char * srcBuff = srcData; + + for (row = 0; row < dstHeight; row++) + { + memcpy(dstBuff, srcBuff, dstWidth ); + + dstBuff += RoundUp4(dstWidth); + srcBuff += dstWidth; + } + } + case 16: + { + result = DecompressPng16(srcData, srcSize, dstWidth, + dstHeight, dstData, byteOrder); + break; + } + case 24: + { + result = DecompressPng24(srcData, srcSize, dstWidth, + dstHeight, dstData, byteOrder); + break; + } + case 32: + { + result = DecompressPng32(srcData, srcSize, dstWidth, + dstHeight, dstData, byteOrder); + break; + } + default: + { + #ifdef PANIC + *logofs << "UnpackPng: PANIC! Error in PNG compression. " + << " Unsupported Bpp value " << dstBpp + << " for the PNG compression" + << ".\n" << logofs_flush; + #endif + + delete [] tmpBuf; + + result = -1; + } + } + + if (result == -1) + { + delete [] tmpBuf; + + return result; + } + + // + // Apply the correction for the brightness + // + + int maskMethod; + + switch (method) + { + case PACK_PNG_8_COLORS: + { + maskMethod = MASK_8_COLORS; + + break; + } + case PACK_PNG_64_COLORS: + { + maskMethod = MASK_64_COLORS; + + break; + } + case PACK_PNG_256_COLORS: + { + maskMethod = MASK_256_COLORS; + + break; + } + case PACK_PNG_512_COLORS: + { + maskMethod = MASK_512_COLORS; + + break; + } + case PACK_PNG_4K_COLORS: + { + maskMethod = MASK_4K_COLORS; + + break; + } + case PACK_PNG_32K_COLORS: + { + maskMethod = MASK_32K_COLORS; + + break; + } + case PACK_PNG_64K_COLORS: + { + maskMethod = MASK_64K_COLORS; + + break; + } + case PACK_PNG_256K_COLORS: + { + maskMethod = MASK_256K_COLORS; + + break; + } + case PACK_PNG_2M_COLORS: + { + maskMethod = MASK_2M_COLORS; + + break; + } + case PACK_PNG_16M_COLORS: + { + maskMethod = MASK_16M_COLORS; + + break; + } + default: + { + #ifdef PANIC + *logofs << "DecompressPng16: PANIC! " + << " No matching decompression method.\n" + << logofs_flush; + #endif + + delete [] tmpBuf; + + return -1; + } + } + + const T_colormask *colorMask = MethodColorMask(maskMethod); + + unsigned char *dstBuff = dstData; + + switch (dstBpp) + { + case 16: + { + Unpack16To16(colorMask, dstBuff, dstBuff, dstBuff + dstSize); + + break; + } + case 24: + { + break; + } + case 32: + { + Unpack32To32(colorMask, (unsigned int *)dstBuff, (unsigned int *)dstBuff, + (unsigned int *)(dstBuff + dstSize)); + break; + } + default: + { + #ifdef PANIC + *logofs << "DecompressPng16: PANIC! " + << " No matching destination bits per plane.\n" + << logofs_flush; + #endif + + delete [] tmpBuf; + + return -1; + } + } + + delete [] tmpBuf; + + return 1; +} + + +// +// Functions that actually do +// the PNG decompression. +// + +int DecompressPng16(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) +{ + unsigned char *data; + unsigned int dx, dy; + + png_structp pngPtr; + png_infop infoPtr; + png_bytep rowPointers; + + + streamPos = 0; + + pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!pngPtr) + { + #ifdef PANIC + *logofs << "DecompressPng16: PANIC! " + << " Failed png_create_read_struct operation" + << ".\n" << logofs_flush; + #endif + + return -1; + } + + infoPtr = png_create_info_struct(pngPtr); + + if (!infoPtr) + { + #ifdef PANIC + *logofs << "DecompressPng16: PANIC! " + << "Failed png_create_info_struct operation" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, NULL, NULL); + + return -1; + } + + if (setjmp(png_jmpbuf(pngPtr))) + { + #ifdef PANIC + *logofs << "DecompressPng16: PANIC! " + << "Error during IO initialization" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + + return -1; + } + + png_set_read_fn(pngPtr, (void *)compressedData, PngReadData); + + if (setjmp(png_jmpbuf(pngPtr))) + { + #ifdef PANIC + *logofs << "DecompressPng16: PANIC! " + << "Error during read of PNG header" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + + return -1; + } + + png_read_info(pngPtr, infoPtr); + + if (png_get_color_type(pngPtr, infoPtr) == PNG_COLOR_TYPE_PALETTE) + { + png_set_expand(pngPtr); + } + + // + // data points to dstBuf which is + // already padded correctly for the final + // image to put + // + + data = dstBuf; + rowPointers = (png_byte *) tmpBuf; + + // + // We use setjmp() to save our context. + // The PNG library will call longjmp() + // in case of error. + // + + if (setjmp(png_jmpbuf(pngPtr))) + { + #ifdef PANIC + *logofs << "DecompressPng16: PANIC! " + << "Error during read of PNG rows" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + + return -1; + } + + unsigned long pixel; + + for (dy = 0; dy < h; dy++) + { + png_read_row(pngPtr, rowPointers, NULL); + + for (dx = 0; dx < w; dx++) + { + pixel = RGB24_TO_PIXEL(16, tmpBuf[dx*3], tmpBuf[dx*3+1], tmpBuf[dx*3+2]); + + // + // Follow the server byte order when arranging data. + // + + if (byteOrder == LSBFirst) + { + data[0] = (unsigned char) (pixel & 0xff); + data[1] = (unsigned char) ((pixel >> 8) & 0xff); + } + else + { + data[1] = (unsigned char) (pixel & 0xff); + data[0] = (unsigned char) ((pixel >> 8) & 0xff); + } + + data += 2; + } + + // + // Move pixelPtr at the beginning of the + // next line. + // + + data = data + (RoundUp4(w * 2) - w * 2); + } + + png_destroy_read_struct(&pngPtr, &infoPtr,NULL); + + #ifdef DEBUG + *logofs << "DecompressPng16: Decompression finished." + << dy << " lines handled.\n" + << logofs_flush; + #endif + + return 1; +} + +int DecompressPng24(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) +{ + static CARD8 *pixelPtr = NULL; + unsigned int dx, dy; + + png_structp pngPtr; + png_infop infoPtr; + png_bytep rowPointers; + + + streamPos = 0; + + pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!pngPtr) + { + #ifdef PANIC + *logofs << "DecompressPng24: PANIC! " + << "Failed png_create_read_struct operation" + << ".\n" << logofs_flush; + #endif + + return -1; + } + + infoPtr = png_create_info_struct(pngPtr); + + if (!infoPtr) + { + #ifdef PANIC + *logofs << "DecompressPng24: PANIC! " + << "Failed png_create_info_struct operation" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, NULL, NULL); + + return -1; + } + + if (setjmp(png_jmpbuf(pngPtr))) + { + #ifdef PANIC + *logofs << "DecompressPng24: PANIC! " + << "Error during IO initialization" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + + return -1; + } + + png_set_read_fn(pngPtr, (void *)compressedData, PngReadData); + + if (setjmp(png_jmpbuf(pngPtr))) + { + #ifdef PANIC + *logofs << "DecompressPng24: PANIC! " + << "Error during read of PNG header" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + + return -1; + } + + png_read_info( pngPtr, infoPtr ) ; + + if (png_get_color_type(pngPtr, infoPtr) == PNG_COLOR_TYPE_PALETTE) + { + png_set_expand(pngPtr); + } + + // + // PixelPtr points to dstBuf which is + // already padded correctly for the final + // image to put + // + + pixelPtr = (CARD8 *) dstBuf; + + rowPointers = (png_byte *)tmpBuf; + + if (setjmp(png_jmpbuf(pngPtr))) + { + #ifdef PANIC + *logofs << "DecompressPng24: PANIC! " + << "Error during read of PNG rows" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + + return -1; + } + + for (dy = 0; dy < h; dy++) + { + png_read_row(pngPtr, rowPointers, NULL); + + for (dx = 0; dx < w; dx++) + { + // + // Follow the server byte order when arranging data. + // + + if (byteOrder == LSBFirst) + { + pixelPtr[0] = tmpBuf[dx * 3]; + pixelPtr[1] = tmpBuf[dx * 3 + 1]; + pixelPtr[2] = tmpBuf[dx * 3 + 2]; + } + else + { + pixelPtr[2] = tmpBuf[dx * 3]; + pixelPtr[1] = tmpBuf[dx * 3 + 1]; + pixelPtr[0] = tmpBuf[dx * 3 + 2]; + } + + pixelPtr += 3; + } + + // + // Go to the next line. + // + + pixelPtr = (CARD8 *) (((char *) pixelPtr) + (RoundUp4(w * 3) - w * 3)); + } + + png_destroy_read_struct(&pngPtr, &infoPtr,NULL); + + #ifdef DEBUG + *logofs << "DecompressPng24: Decompression finished." + << dy << " lines handled.\n" + << logofs_flush; + #endif + + return 1; +} + +int DecompressPng32(unsigned char *compressedData, int compressedLen, + unsigned int w, unsigned int h, unsigned char *dstBuf, int byteOrder) +{ + unsigned char *data; + + unsigned int dx, dy; + + png_structp pngPtr; + png_infop infoPtr; + png_bytep rowPointers; + + streamPos = 0; + + pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!pngPtr) + { + #ifdef PANIC + *logofs << "DecompressPng32: PANIC! " + << "Failed png_create_read_struct operation" + << ".\n" << logofs_flush; + #endif + + return -1; + } + + infoPtr = png_create_info_struct(pngPtr); + + if (!infoPtr) + { + #ifdef PANIC + *logofs << "DecompressPng32: PANIC! " + << "Failed png_create_info_struct operation." + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, NULL, NULL); + + return -1; + } + + if (setjmp(png_jmpbuf(pngPtr))) + { + #ifdef PANIC + *logofs << "DecompressPng32: PANIC! " + << "Error during IO initialization" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + + return -1; + } + + png_set_read_fn(pngPtr, (void *)compressedData, PngReadData); + + if (setjmp(png_jmpbuf(pngPtr))) + { + #ifdef PANIC + *logofs << "DecompressPng32: PANIC! " + << "Error during read of PNG header" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + + return -1; + } + + png_read_info(pngPtr, infoPtr) ; + + + if (png_get_color_type(pngPtr, infoPtr) == PNG_COLOR_TYPE_PALETTE) + { + png_set_expand(pngPtr); + } + + // + // data points to dstBuf which is + // already padded correctly for the final + // image to put + // + + data = dstBuf; + + rowPointers = (png_byte *) tmpBuf; + + if (setjmp(png_jmpbuf(pngPtr))) + { + #ifdef PANIC + *logofs << "DecompressPng32: PANIC! " + << "Error during read of PNG rows" + << ".\n" << logofs_flush; + #endif + + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + + return -1; + } + + unsigned long pixel; + + int i; + + for (dy = 0; dy < h; dy++) + { + png_read_row(pngPtr, rowPointers, NULL); + + for (dx = 0; dx < w; dx++) + { + pixel = RGB24_TO_PIXEL(32, tmpBuf[dx * 3], tmpBuf[dx * 3 + 1], + tmpBuf[dx * 3 + 2]); + + // + // Follow the server byte order when arranging data. + // + + if (byteOrder == LSBFirst) + { + for (i = 0; i < 4; i++) + { + data[i] = (unsigned char)(pixel & 0xff); + pixel >>= 8; + } + } + else + { + for (i = 3; i >= 0; i--) + { + data[i] = (unsigned char) (pixel & 0xff); + pixel >>= 8; + } + } + + data += 4; + } + } + + png_destroy_read_struct(&pngPtr, &infoPtr,NULL); + + #ifdef DEBUG + *logofs << "DecompressPng32: Decompression finished." + << dy << " lines handled.\n" + << logofs_flush; + #endif + + return 1; +} + +static void PngReadData(png_structp png_ptr, png_bytep data, png_size_t length) +{ + memcpy((char *) data, (char *) png_get_io_ptr(png_ptr) + streamPos, length); + + streamPos += length; +} diff --git a/nxcomp/src/Pgn.h b/nxcomp/src/Pgn.h new file mode 100644 index 000000000..e5ea36715 --- /dev/null +++ b/nxcomp/src/Pgn.h @@ -0,0 +1,42 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Pgn_H +#define Pgn_H + +// +// This file obviously supports PNG +// decompression. It was renamed to +// avoid name clashes on Windows. +// + +#include "Misc.h" +#include "Unpack.h" + +int UnpackPng(T_geometry *geometry, unsigned char method, unsigned char *srcData, + int srcSize, int dstBpp, int dstWidth, int dstHeight, + unsigned char *dstData, int dstSize); + +#endif /* Pgn_H */ diff --git a/nxcomp/src/Pipe.cpp b/nxcomp/src/Pipe.cpp new file mode 100644 index 000000000..4fa149412 --- /dev/null +++ b/nxcomp/src/Pipe.cpp @@ -0,0 +1,433 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "Pipe.h" +#include "Misc.h" +#include "Fork.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +extern void RegisterChild(int child); + +static int Psplit(const char *command, char *parameters[], int limit); + +// +// These are slightly modified versions of popen(3) and pclose(3) +// that don't rely on a shell to be available on the system, so +// that they can also work on Windows. As an additional benefit, +// these functions give up all privileges before running the com- +// mand. Code is taken from the X distribution and, in turn, is +// based on libc from FreeBSD 2.2. +// + +static struct pid +{ + struct pid *next; + FILE *fp; + int self; + +} *pidlist; + +// +// A very unsofisticated attempt to parse the command line and +// split each parameter in distinct strings. This is not going +// to work when dealing with parameters containing spaces, even +// if they are enclosed in quotes. +// + +int Psplit(const char *command, char *parameters[], int limit) +{ + char *line; + char *value; + + int number; + + // + // Preapare the list of parameters. + // + + for (number = 0; number < limit; number++) + { + parameters[number] = NULL; + } + + // + // Copy the command to get rid of the + // const qualifier. + // + + line = new char[strlen(command) + 1]; + + if (line == NULL) + { + goto PsplitError; + } + + strcpy(line, command); + + number = 0; + + value = strtok(line, " "); + + while (value != NULL && number < limit) + { + #ifdef DEBUG + *logofs << "Psplit: Got parameter '" << value + << "'.\n" << logofs_flush; + #endif + + parameters[number] = new char[strlen(value) + 1]; + + if (parameters[number] == NULL) + { + goto PsplitError; + } + + strcpy(parameters[number], value); + + number++; + + // + // If this is the first parameter, then + // copy it in the second position and + // use it as the name of the command. + // + + if (number == 1) + { + parameters[number] = new char[strlen(value) + 1]; + + if (parameters[number] == NULL) + { + goto PsplitError; + } + + strcpy(parameters[number], value); + + number++; + } + + value = strtok(NULL, " "); + } + + // + // Needs at least to have the command itself and + // the first argument, being again the name of + // the command. + // + + if (number < 2) + { + goto PsplitError; + } + + return number; + +PsplitError: + + #ifdef PANIC + *logofs << "Psplit: PANIC! Can't split command line '" + << command << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't split command line '" + << command << "'.\n"; + + delete [] line; + + return -1; +} + +FILE *Popen(char * const parameters[], const char *type) +{ + FILE *iop; + + struct pid *cur; + int pdes[2], pid; + + if (parameters == NULL || type == NULL) + { + return NULL; + } + + if ((*type != 'r' && *type != 'w') || type[1]) + { + return NULL; + } + + if ((cur = (struct pid *) malloc(sizeof(struct pid))) == NULL) + { + return NULL; + } + + if (pipe(pdes) < 0) + { + free(cur); + + return NULL; + } + + // + // Block all signals until command is exited. + // We need to gather information about the + // child in Pclose(). + // + + DisableSignals(); + + switch (pid = Fork()) + { + case -1: + { + // + // Error. + // + + #ifdef PANIC + *logofs << "Popen: PANIC! Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Function fork failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + close(pdes[0]); + close(pdes[1]); + + free(cur); + + return NULL; + } + case 0: + { + // + // Child. + // + + struct passwd *pwent = getpwuid(getuid()); + if (pwent) initgroups(pwent->pw_name,getgid()); + if (setgid(getgid()) == -1) + { + _exit(127); + } + if (setuid(getuid()) == -1) + { + _exit(127); + } + + if (*type == 'r') + { + if (pdes[1] != 1) + { + // + // Set up stdout. + // + + dup2(pdes[1], 1); + close(pdes[1]); + } + + close(pdes[0]); + } + else + { + if (pdes[0] != 0) + { + // + // Set up stdin. + // + + dup2(pdes[0], 0); + close(pdes[0]); + } + + close(pdes[1]); + } + + execvp(parameters[0], parameters + 1); + + exit(127); + } + } + + // + // Parent. Save data about the child. + // + + RegisterChild(pid); + + if (*type == 'r') + { + iop = fdopen(pdes[0], type); + + close(pdes[1]); + } + else + { + iop = fdopen(pdes[1], type); + + close(pdes[0]); + } + + cur -> fp = iop; + cur -> self = pid; + cur -> next = pidlist; + + pidlist = cur; + + #ifdef TEST + *logofs << "Popen: Executing "; + + for (int i = 0; i < 256 && parameters[i] != NULL; i++) + { + *logofs << "[" << parameters[i] << "]"; + } + + *logofs << " with descriptor " << fileno(iop) + << ".\n" << logofs_flush; + #endif + + return iop; +} + +FILE *Popen(const char *command, const char *type) +{ + char *parameters[256]; + + if (Psplit(command, parameters, 256) > 0) + { + FILE *file = Popen(parameters, type); + + for (int i = 0; i < 256; i++) + { + delete [] parameters[i]; + } + + return file; + } + else + { + #ifdef PANIC + *logofs << "Popen: PANIC! Failed to parse command '" + << command << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to parse command '" + << command << "'.\n"; + + return NULL; + } +} + +int Pclose(FILE *iop) +{ + struct pid *cur, *last; + + int pstat; + int pid; + + #ifdef TEST + *logofs << "Pclose: Closing command with output " + << "on descriptor " << fileno(iop) << ".\n" + << logofs_flush; + #endif + + fclose((FILE *) iop); + + for (last = NULL, cur = pidlist; cur; last = cur, cur = cur -> next) + { + if (cur -> fp == iop) + { + break; + } + } + + if (cur == NULL) + { + #ifdef PANIC + *logofs << "Pclose: PANIC! Failed to find the process " + << "for descriptor " << fileno(iop) << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed to find the process " + << "for descriptor " << fileno(iop) << ".\n"; + + return -1; + } + + do + { + #ifdef TEST + *logofs << "Pclose: Going to wait for process " + << "with pid '" << cur -> self << "'.\n" + << logofs_flush; + #endif + + pid = waitpid(cur -> self, &pstat, 0); + } + while (pid == -1 && errno == EINTR); + + if (last == NULL) + { + pidlist = cur -> next; + } + else + { + last -> next = cur -> next; + } + + free(cur); + + // + // Child has finished and we called the + // waitpid(). We can enable signals again. + // + + EnableSignals(); + + return (pid == -1 ? -1 : pstat); +} diff --git a/nxcomp/src/Pipe.h b/nxcomp/src/Pipe.h new file mode 100644 index 000000000..fd1061d30 --- /dev/null +++ b/nxcomp/src/Pipe.h @@ -0,0 +1,35 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +// +// These are slightly modified versions of popen(3) and pclose(3) +// that don't rely on a shell to be available on the system, so +// that they can also work on Windows. +// + +extern FILE *Popen(char * const parameters[], const char *type); +extern FILE *Popen(const char *command, const char *type); + +extern int Pclose(FILE *file); diff --git a/nxcomp/src/PolyArc.cpp b/nxcomp/src/PolyArc.cpp new file mode 100644 index 000000000..42dbb265d --- /dev/null +++ b/nxcomp/src/PolyArc.cpp @@ -0,0 +1,162 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PolyArc.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int PolyArcStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyArcMessage *polyArc = (PolyArcMessage *) message; + + // + // Here is the fingerprint. + // + + polyArc -> drawable = GetULONG(buffer + 4, bigEndian); + polyArc -> gcontext = GetULONG(buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PolyArcStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyArcMessage *polyArc = (PolyArcMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(polyArc -> drawable, buffer + 4, bigEndian); + PutULONG(polyArc -> gcontext, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PolyArcStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PolyArcMessage *polyArc = (PolyArcMessage *) message; + + *logofs << name() << ": Identity drawable " << polyArc -> drawable + << ", gcontext " << polyArc -> gcontext + << ", size " << polyArc -> size_ << ".\n" << logofs_flush; + #endif +} + +void PolyArcStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +} + +void PolyArcStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + PolyArcMessage *polyArc = (PolyArcMessage *) message; + PolyArcMessage *cachedPolyArc = (PolyArcMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyArc -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyArc -> drawable, clientCache -> drawableCache); + + cachedPolyArc -> drawable = polyArc -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyArc -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyArc -> gcontext, clientCache -> gcCache); + + cachedPolyArc -> gcontext = polyArc -> gcontext; +} + +void PolyArcStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + PolyArcMessage *polyArc = (PolyArcMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + polyArc -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyArc -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + polyArc -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyArc -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/PolyArc.h b/nxcomp/src/PolyArc.h new file mode 100644 index 000000000..d744d6a10 --- /dev/null +++ b/nxcomp/src/PolyArc.h @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PolyArc_H +#define PolyArc_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define POLYARC_ENABLE_CACHE 1 +#define POLYARC_ENABLE_DATA 0 +#define POLYARC_ENABLE_SPLIT 0 +#define POLYARC_ENABLE_COMPRESS 0 + +#define POLYARC_DATA_LIMIT 1980 +#define POLYARC_DATA_OFFSET 12 + +#define POLYARC_CACHE_SLOTS 2000 +#define POLYARC_CACHE_THRESHOLD 2 +#define POLYARC_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class PolyArcMessage : public Message +{ + friend class PolyArcStore; + + public: + + PolyArcMessage() + { + } + + ~PolyArcMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int drawable; + unsigned int gcontext; +}; + +class PolyArcStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + PolyArcStore() : MessageStore() + { + enableCache = POLYARC_ENABLE_CACHE; + enableData = POLYARC_ENABLE_DATA; + enableSplit = POLYARC_ENABLE_SPLIT; + enableCompress = POLYARC_ENABLE_COMPRESS; + + dataLimit = POLYARC_DATA_LIMIT; + dataOffset = POLYARC_DATA_OFFSET; + + cacheSlots = POLYARC_CACHE_SLOTS; + cacheThreshold = POLYARC_CACHE_THRESHOLD; + cacheLowerThreshold = POLYARC_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~PolyArcStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "PolyArc"; + } + + virtual unsigned char opcode() const + { + return X_PolyArc; + } + + virtual unsigned int storage() const + { + return sizeof(PolyArcMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new PolyArcMessage(); + } + + virtual Message *create(const Message &message) const + { + return new PolyArcMessage((const PolyArcMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (PolyArcMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PolyArc_H */ diff --git a/nxcomp/src/PolyFillArc.cpp b/nxcomp/src/PolyFillArc.cpp new file mode 100644 index 000000000..35125f0d3 --- /dev/null +++ b/nxcomp/src/PolyFillArc.cpp @@ -0,0 +1,162 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PolyFillArc.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int PolyFillArcStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; + + // + // Here is the fingerprint. + // + + polyFillArc -> drawable = GetULONG(buffer + 4, bigEndian); + polyFillArc -> gcontext = GetULONG(buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PolyFillArcStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(polyFillArc -> drawable, buffer + 4, bigEndian); + PutULONG(polyFillArc -> gcontext, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PolyFillArcStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; + + *logofs << name() << ": Identity drawable " << polyFillArc -> drawable + << ", gcontext " << polyFillArc -> gcontext + << ", size " << polyFillArc -> size_ << ".\n" << logofs_flush; + #endif +} + +void PolyFillArcStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +} + +void PolyFillArcStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; + PolyFillArcMessage *cachedPolyFillArc = (PolyFillArcMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyFillArc -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyFillArc -> drawable, clientCache -> drawableCache); + + cachedPolyFillArc -> drawable = polyFillArc -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyFillArc -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyFillArc -> gcontext, clientCache -> gcCache); + + cachedPolyFillArc -> gcontext = polyFillArc -> gcontext; +} + +void PolyFillArcStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + PolyFillArcMessage *polyFillArc = (PolyFillArcMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + polyFillArc -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyFillArc -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + polyFillArc -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyFillArc -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/PolyFillArc.h b/nxcomp/src/PolyFillArc.h new file mode 100644 index 000000000..a4eff5b48 --- /dev/null +++ b/nxcomp/src/PolyFillArc.h @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PolyFillArc_H +#define PolyFillArc_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define POLYFILLARC_ENABLE_CACHE 1 +#define POLYFILLARC_ENABLE_DATA 0 +#define POLYFILLARC_ENABLE_SPLIT 0 +#define POLYFILLARC_ENABLE_COMPRESS 0 + +#define POLYFILLARC_DATA_LIMIT 6144 +#define POLYFILLARC_DATA_OFFSET 12 + +#define POLYFILLARC_CACHE_SLOTS 2000 +#define POLYFILLARC_CACHE_THRESHOLD 2 +#define POLYFILLARC_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class PolyFillArcMessage : public Message +{ + friend class PolyFillArcStore; + + public: + + PolyFillArcMessage() + { + } + + ~PolyFillArcMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int drawable; + unsigned int gcontext; +}; + +class PolyFillArcStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + PolyFillArcStore() : MessageStore() + { + enableCache = POLYFILLARC_ENABLE_CACHE; + enableData = POLYFILLARC_ENABLE_DATA; + enableSplit = POLYFILLARC_ENABLE_SPLIT; + enableCompress = POLYFILLARC_ENABLE_COMPRESS; + + dataLimit = POLYFILLARC_DATA_LIMIT; + dataOffset = POLYFILLARC_DATA_OFFSET; + + cacheSlots = POLYFILLARC_CACHE_SLOTS; + cacheThreshold = POLYFILLARC_CACHE_THRESHOLD; + cacheLowerThreshold = POLYFILLARC_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~PolyFillArcStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "PolyFillArc"; + } + + virtual unsigned char opcode() const + { + return X_PolyFillArc; + } + + virtual unsigned int storage() const + { + return sizeof(PolyFillArcMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new PolyFillArcMessage(); + } + + virtual Message *create(const Message &message) const + { + return new PolyFillArcMessage((const PolyFillArcMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (PolyFillArcMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PolyFillArc_H */ diff --git a/nxcomp/src/PolyFillRectangle.cpp b/nxcomp/src/PolyFillRectangle.cpp new file mode 100644 index 000000000..95694e582 --- /dev/null +++ b/nxcomp/src/PolyFillRectangle.cpp @@ -0,0 +1,160 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PolyFillRectangle.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int PolyFillRectangleStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; + + // + // Here is the fingerprint. + // + + polyFillRectangle -> drawable = GetULONG(buffer + 4, bigEndian); + polyFillRectangle -> gcontext = GetULONG(buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PolyFillRectangleStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(polyFillRectangle -> drawable, buffer + 4, bigEndian); + PutULONG(polyFillRectangle -> gcontext, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PolyFillRectangleStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; + + *logofs << name() << ": Identity drawable " << polyFillRectangle -> drawable + << ", gcontext " << polyFillRectangle -> gcontext + << ", size " << polyFillRectangle -> size_ << ".\n" << logofs_flush; + #endif +} + +void PolyFillRectangleStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +} + +void PolyFillRectangleStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; + PolyFillRectangleMessage *cachedPolyFillRectangle = (PolyFillRectangleMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding value " << polyFillRectangle -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyFillRectangle -> drawable, clientCache -> drawableCache); + + cachedPolyFillRectangle -> drawable = polyFillRectangle -> drawable; + + #ifdef DEBUG + *logofs << name() << ": Encoding value " << polyFillRectangle -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyFillRectangle -> gcontext, clientCache -> gcCache); + + cachedPolyFillRectangle -> gcontext = polyFillRectangle -> gcontext; +} + +void PolyFillRectangleStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + PolyFillRectangleMessage *polyFillRectangle = (PolyFillRectangleMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + polyFillRectangle -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyFillRectangle -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + polyFillRectangle -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyFillRectangle -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/PolyFillRectangle.h b/nxcomp/src/PolyFillRectangle.h new file mode 100644 index 000000000..7ebb9270d --- /dev/null +++ b/nxcomp/src/PolyFillRectangle.h @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PolyFillRectangle_H +#define PolyFillRectangle_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define POLYFILLRECTANGLE_ENABLE_CACHE 1 +#define POLYFILLRECTANGLE_ENABLE_DATA 0 +#define POLYFILLRECTANGLE_ENABLE_SPLIT 0 +#define POLYFILLRECTANGLE_ENABLE_COMPRESS 0 + +#define POLYFILLRECTANGLE_DATA_LIMIT 2048 +#define POLYFILLRECTANGLE_DATA_OFFSET 12 + +#define POLYFILLRECTANGLE_CACHE_SLOTS 4000 +#define POLYFILLRECTANGLE_CACHE_THRESHOLD 5 +#define POLYFILLRECTANGLE_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class PolyFillRectangleMessage : public Message +{ + friend class PolyFillRectangleStore; + + public: + + PolyFillRectangleMessage() + { + } + + ~PolyFillRectangleMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int drawable; + unsigned int gcontext; +}; + +class PolyFillRectangleStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + PolyFillRectangleStore() : MessageStore() + { + enableCache = POLYFILLRECTANGLE_ENABLE_CACHE; + enableData = POLYFILLRECTANGLE_ENABLE_DATA; + enableSplit = POLYFILLRECTANGLE_ENABLE_SPLIT; + enableCompress = POLYFILLRECTANGLE_ENABLE_COMPRESS; + + dataLimit = POLYFILLRECTANGLE_DATA_LIMIT; + dataOffset = POLYFILLRECTANGLE_DATA_OFFSET; + + cacheSlots = POLYFILLRECTANGLE_CACHE_SLOTS; + cacheThreshold = POLYFILLRECTANGLE_CACHE_THRESHOLD; + cacheLowerThreshold = POLYFILLRECTANGLE_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~PolyFillRectangleStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "PolyFillRectangle"; + } + + virtual unsigned char opcode() const + { + return X_PolyFillRectangle; + } + + virtual unsigned int storage() const + { + return sizeof(PolyFillRectangleMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new PolyFillRectangleMessage(); + } + + virtual Message *create(const Message &message) const + { + return new PolyFillRectangleMessage((const PolyFillRectangleMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (PolyFillRectangleMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PolyFillRectangle_H */ diff --git a/nxcomp/src/PolyLine.cpp b/nxcomp/src/PolyLine.cpp new file mode 100644 index 000000000..1b12bbe98 --- /dev/null +++ b/nxcomp/src/PolyLine.cpp @@ -0,0 +1,168 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PolyLine.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int PolyLineStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyLineMessage *polyLine = (PolyLineMessage *) message; + + // + // Here is the fingerprint. + // + + polyLine -> mode = *(buffer + 1); + + polyLine -> drawable = GetULONG(buffer + 4, bigEndian); + polyLine -> gcontext = GetULONG(buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PolyLineStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyLineMessage *polyLine = (PolyLineMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = polyLine -> mode; + + PutULONG(polyLine -> drawable, buffer + 4, bigEndian); + PutULONG(polyLine -> gcontext, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PolyLineStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PolyLineMessage *polyLine = (PolyLineMessage *) message; + + *logofs << name() << ": Identity drawable " << polyLine -> drawable + << ", gcontext " << polyLine -> gcontext + << ", size " << polyLine -> size_ << ".\n" << logofs_flush; + #endif +} + +void PolyLineStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // Since ProtoStep8 (#issue 108) + md5_append(md5_state_, buffer + 1, 1); +} + +void PolyLineStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + PolyLineMessage *polyLine = (PolyLineMessage *) message; + PolyLineMessage *cachedPolyLine = (PolyLineMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyLine -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyLine -> drawable, clientCache -> drawableCache); + + cachedPolyLine -> drawable = polyLine -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyLine -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyLine -> gcontext, clientCache -> gcCache); + + cachedPolyLine -> gcontext = polyLine -> gcontext; +} + +void PolyLineStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + PolyLineMessage *polyLine = (PolyLineMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + polyLine -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyLine -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + polyLine -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyLine -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/PolyLine.h b/nxcomp/src/PolyLine.h new file mode 100644 index 000000000..66fa5df1a --- /dev/null +++ b/nxcomp/src/PolyLine.h @@ -0,0 +1,186 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PolyLine_H +#define PolyLine_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define POLYLINE_ENABLE_CACHE 1 +#define POLYLINE_ENABLE_DATA 0 +#define POLYLINE_ENABLE_SPLIT 0 +#define POLYLINE_ENABLE_COMPRESS 0 + +#define POLYLINE_DATA_LIMIT 144 +#define POLYLINE_DATA_OFFSET 12 + +#define POLYLINE_CACHE_SLOTS 3000 +#define POLYLINE_CACHE_THRESHOLD 3 +#define POLYLINE_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class PolyLineMessage : public Message +{ + friend class PolyLineStore; + + public: + + PolyLineMessage() + { + } + + ~PolyLineMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char mode; + unsigned int drawable; + unsigned int gcontext; +}; + +class PolyLineStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + PolyLineStore() : MessageStore() + { + enableCache = POLYLINE_ENABLE_CACHE; + enableData = POLYLINE_ENABLE_DATA; + enableSplit = POLYLINE_ENABLE_SPLIT; + enableCompress = POLYLINE_ENABLE_COMPRESS; + + dataLimit = POLYLINE_DATA_LIMIT; + dataOffset = POLYLINE_DATA_OFFSET; + + cacheSlots = POLYLINE_CACHE_SLOTS; + cacheThreshold = POLYLINE_CACHE_THRESHOLD; + cacheLowerThreshold = POLYLINE_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~PolyLineStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "PolyLine"; + } + + virtual unsigned char opcode() const + { + return X_PolyLine; + } + + virtual unsigned int storage() const + { + return sizeof(PolyLineMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new PolyLineMessage(); + } + + virtual Message *create(const Message &message) const + { + return new PolyLineMessage((const PolyLineMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (PolyLineMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PolyLine_H */ diff --git a/nxcomp/src/PolyPoint.cpp b/nxcomp/src/PolyPoint.cpp new file mode 100644 index 000000000..70151cc0d --- /dev/null +++ b/nxcomp/src/PolyPoint.cpp @@ -0,0 +1,168 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PolyPoint.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int PolyPointStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyPointMessage *polyPoint = (PolyPointMessage *) message; + + // + // Here is the fingerprint. + // + + polyPoint -> mode = *(buffer + 1); + + polyPoint -> drawable = GetULONG(buffer + 4, bigEndian); + polyPoint -> gcontext = GetULONG(buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PolyPointStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyPointMessage *polyPoint = (PolyPointMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = polyPoint -> mode; + + PutULONG(polyPoint -> drawable, buffer + 4, bigEndian); + PutULONG(polyPoint -> gcontext, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PolyPointStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PolyPointMessage *polyPoint = (PolyPointMessage *) message; + + *logofs << name() << ": Identity drawable " << polyPoint -> drawable + << ", gcontext " << polyPoint -> gcontext + << ", size " << polyPoint -> size_ << ".\n" << logofs_flush; + #endif +} + +void PolyPointStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // Since ProtoStep8 (#issue 108) + md5_append(md5_state_, buffer + 1, 1); +} + +void PolyPointStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + PolyPointMessage *polyPoint = (PolyPointMessage *) message; + PolyPointMessage *cachedPolyPoint = (PolyPointMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyPoint -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyPoint -> drawable, clientCache -> drawableCache); + + cachedPolyPoint -> drawable = polyPoint -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyPoint -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyPoint -> gcontext, clientCache -> gcCache); + + cachedPolyPoint -> gcontext = polyPoint -> gcontext; +} + +void PolyPointStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + PolyPointMessage *polyPoint = (PolyPointMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + polyPoint -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyPoint -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + polyPoint -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyPoint -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/PolyPoint.h b/nxcomp/src/PolyPoint.h new file mode 100644 index 000000000..b8ea183bf --- /dev/null +++ b/nxcomp/src/PolyPoint.h @@ -0,0 +1,186 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PolyPoint_H +#define PolyPoint_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define POLYPOINT_ENABLE_CACHE 1 +#define POLYPOINT_ENABLE_DATA 0 +#define POLYPOINT_ENABLE_SPLIT 0 +#define POLYPOINT_ENABLE_COMPRESS 0 + +#define POLYPOINT_DATA_LIMIT 3200 +#define POLYPOINT_DATA_OFFSET 12 + +#define POLYPOINT_CACHE_SLOTS 3000 +#define POLYPOINT_CACHE_THRESHOLD 3 +#define POLYPOINT_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class PolyPointMessage : public Message +{ + friend class PolyPointStore; + + public: + + PolyPointMessage() + { + } + + ~PolyPointMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char mode; + unsigned int drawable; + unsigned int gcontext; +}; + +class PolyPointStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + PolyPointStore() : MessageStore() + { + enableCache = POLYPOINT_ENABLE_CACHE; + enableData = POLYPOINT_ENABLE_DATA; + enableSplit = POLYPOINT_ENABLE_SPLIT; + enableCompress = POLYPOINT_ENABLE_COMPRESS; + + dataLimit = POLYPOINT_DATA_LIMIT; + dataOffset = POLYPOINT_DATA_OFFSET; + + cacheSlots = POLYPOINT_CACHE_SLOTS; + cacheThreshold = POLYPOINT_CACHE_THRESHOLD; + cacheLowerThreshold = POLYPOINT_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~PolyPointStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "PolyPoint"; + } + + virtual unsigned char opcode() const + { + return X_PolyPoint; + } + + virtual unsigned int storage() const + { + return sizeof(PolyPointMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new PolyPointMessage(); + } + + virtual Message *create(const Message &message) const + { + return new PolyPointMessage((const PolyPointMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (PolyPointMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PolyPoint_H */ diff --git a/nxcomp/src/PolySegment.cpp b/nxcomp/src/PolySegment.cpp new file mode 100644 index 000000000..aa2d4efe3 --- /dev/null +++ b/nxcomp/src/PolySegment.cpp @@ -0,0 +1,162 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PolySegment.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int PolySegmentStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolySegmentMessage *polySegment = (PolySegmentMessage *) message; + + // + // Here is the fingerprint. + // + + polySegment -> drawable = GetULONG(buffer + 4, bigEndian); + polySegment -> gcontext = GetULONG(buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PolySegmentStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolySegmentMessage *polySegment = (PolySegmentMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(polySegment -> drawable, buffer + 4, bigEndian); + PutULONG(polySegment -> gcontext, buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PolySegmentStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PolySegmentMessage *polySegment = (PolySegmentMessage *) message; + + *logofs << name() << ": Identity drawable " << polySegment -> drawable + << ", gcontext " << polySegment -> gcontext + << ", size " << polySegment -> size_ << ".\n" << logofs_flush; + #endif +} + +void PolySegmentStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +} + +void PolySegmentStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + PolySegmentMessage *polySegment = (PolySegmentMessage *) message; + PolySegmentMessage *cachedPolySegment = (PolySegmentMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polySegment -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polySegment -> drawable, clientCache -> drawableCache); + + cachedPolySegment -> drawable = polySegment -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polySegment -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polySegment -> gcontext, clientCache -> gcCache); + + cachedPolySegment -> gcontext = polySegment -> gcontext; +} + +void PolySegmentStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + PolySegmentMessage *polySegment = (PolySegmentMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + polySegment -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polySegment -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + polySegment -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polySegment -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/PolySegment.h b/nxcomp/src/PolySegment.h new file mode 100644 index 000000000..53fd42c60 --- /dev/null +++ b/nxcomp/src/PolySegment.h @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PolySegment_H +#define PolySegment_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define POLYSEGMENT_ENABLE_CACHE 1 +#define POLYSEGMENT_ENABLE_DATA 0 +#define POLYSEGMENT_ENABLE_SPLIT 0 +#define POLYSEGMENT_ENABLE_COMPRESS 0 + +#define POLYSEGMENT_DATA_LIMIT 8192 +#define POLYSEGMENT_DATA_OFFSET 12 + +#define POLYSEGMENT_CACHE_SLOTS 3000 +#define POLYSEGMENT_CACHE_THRESHOLD 5 +#define POLYSEGMENT_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class PolySegmentMessage : public Message +{ + friend class PolySegmentStore; + + public: + + PolySegmentMessage() + { + } + + ~PolySegmentMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int drawable; + unsigned int gcontext; +}; + +class PolySegmentStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + PolySegmentStore() : MessageStore() + { + enableCache = POLYSEGMENT_ENABLE_CACHE; + enableData = POLYSEGMENT_ENABLE_DATA; + enableSplit = POLYSEGMENT_ENABLE_SPLIT; + enableCompress = POLYSEGMENT_ENABLE_COMPRESS; + + dataLimit = POLYSEGMENT_DATA_LIMIT; + dataOffset = POLYSEGMENT_DATA_OFFSET; + + cacheSlots = POLYSEGMENT_CACHE_SLOTS; + cacheThreshold = POLYSEGMENT_CACHE_THRESHOLD; + cacheLowerThreshold = POLYSEGMENT_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~PolySegmentStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "PolySegment"; + } + + virtual unsigned char opcode() const + { + return X_PolySegment; + } + + virtual unsigned int storage() const + { + return sizeof(PolySegmentMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new PolySegmentMessage(); + } + + virtual Message *create(const Message &message) const + { + return new PolySegmentMessage((const PolySegmentMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (PolySegmentMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PolySegment_H */ diff --git a/nxcomp/src/PolyText16.cpp b/nxcomp/src/PolyText16.cpp new file mode 100644 index 000000000..32be45482 --- /dev/null +++ b/nxcomp/src/PolyText16.cpp @@ -0,0 +1,312 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PolyText16.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int PolyText16Store::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyText16Message *polyText16 = (PolyText16Message *) message; + + // + // Here is the fingerprint. + // + + polyText16 -> drawable = GetULONG(buffer + 4, bigEndian); + polyText16 -> gcontext = GetULONG(buffer + 8, bigEndian); + + polyText16 -> x = GetUINT(buffer + 12, bigEndian); + polyText16 -> y = GetUINT(buffer + 14, bigEndian); + + // + // Clean up padding bytes. + // + + #ifdef DUMP + + DumpData(buffer, size); + + *logofs << "\n" << logofs_flush; + + #endif + + if ((int) size > dataOffset) + { + int current; + int length; + int delta; + int item; + + unsigned int nitem; + + unsigned char *pad = NULL; + unsigned char *end = NULL; + + delta = 1; + nitem = 0; + + #ifdef DUMP + *logofs << name() << " Size " << size << ".\n" << logofs_flush; + #endif + + // + // Data is a list of TextItem where element + // can be a string or a font shift. + // + + current = POLYTEXT16_DATA_OFFSET; + length = POLYTEXT16_DATA_OFFSET; + + do + { + #ifdef DUMP + *logofs << name() << " Current " << current << ".\n" << logofs_flush; + #endif + + item = GetUINT(buffer + length , bigEndian); + + if (item < 255) + { + // + // Text element. Number represents + // the 'Length of CHAR2B string' + // field. + // + + length += ((item * 2) + delta + 1); + + nitem++; + } + else if (item == 255) + { + // + // Element is a font shift. + // + + length += 5; + + nitem++; + } + + #ifdef DUMP + *logofs << name() << " Item " << item << ".\n" << logofs_flush; + #endif + + current += length; + } + while(current < (int) size && item != 0); + + #ifdef DUMP + *logofs << name() << " Final length " << length << ".\n" << logofs_flush; + #endif + + end = ((unsigned char *) buffer) + size; + + pad = ((unsigned char *) buffer) + length; + + for (; pad < end && nitem >= 1; pad++) + { + #ifdef DUMP + *logofs << name() << " Padding " << " .\n" << logofs_flush; + #endif + + *pad = 0; + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PolyText16Store::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyText16Message *polyText16 = (PolyText16Message *) message; + + // + // Fill all the message's fields. + // + + PutULONG(polyText16 -> drawable, buffer + 4, bigEndian); + PutULONG(polyText16 -> gcontext, buffer + 8, bigEndian); + + PutUINT(polyText16 -> x, buffer + 12, bigEndian); + PutUINT(polyText16 -> y, buffer + 14, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PolyText16Store::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PolyText16Message *polyText16 = (PolyText16Message *) message; + + *logofs << name() << ": Identity drawable " << polyText16 -> drawable + << ", gcontext " << polyText16 -> gcontext << ", x " << polyText16 -> x + << ", y " << polyText16 -> y << ", size " << polyText16 -> size_ + << ".\n"; + + #endif +} + +void PolyText16Store::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +} + +void PolyText16Store::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + PolyText16Message *polyText16 = (PolyText16Message *) message; + PolyText16Message *cachedPolyText16 = (PolyText16Message *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyText16 -> drawable + << " as " << "drawable" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyText16 -> drawable, clientCache -> drawableCache); + + cachedPolyText16 -> drawable = polyText16 -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyText16 -> gcontext + << " as " << "gcontext" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyText16 -> gcontext, clientCache -> gcCache); + + cachedPolyText16 -> gcontext = polyText16 -> gcontext; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyText16 -> x + << " as " << "x" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_x = polyText16 -> x - cachedPolyText16 -> x; + + encodeBuffer.encodeCachedValue(diff_x, 16, + clientCache -> polyTextCacheX); + + cachedPolyText16 -> x = polyText16 -> x; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyText16 -> y + << " as " << "y" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_y = polyText16 -> y - cachedPolyText16 -> y; + + encodeBuffer.encodeCachedValue(diff_y, 16, + clientCache -> polyTextCacheY); + + cachedPolyText16 -> y = polyText16 -> y; +} + +void PolyText16Store::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + PolyText16Message *polyText16 = (PolyText16Message *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + polyText16 -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyText16 -> drawable + << " as " << "drawable" << " field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + polyText16 -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyText16 -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> polyTextCacheX); + + polyText16 -> x += value; + polyText16 -> x &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyText16 -> x + << " as x field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> polyTextCacheY); + + polyText16 -> y += value; + polyText16 -> y &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyText16 -> y + << " as y field.\n" << logofs_flush; + #endif +} + + diff --git a/nxcomp/src/PolyText16.h b/nxcomp/src/PolyText16.h new file mode 100644 index 000000000..805e1fa04 --- /dev/null +++ b/nxcomp/src/PolyText16.h @@ -0,0 +1,188 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PolyText16_H +#define PolyText16_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define POLYTEXT16_ENABLE_CACHE 1 +#define POLYTEXT16_ENABLE_DATA 0 +#define POLYTEXT16_ENABLE_SPLIT 0 +#define POLYTEXT16_ENABLE_COMPRESS 0 + +#define POLYTEXT16_DATA_LIMIT 420 +#define POLYTEXT16_DATA_OFFSET 16 + +#define POLYTEXT16_CACHE_SLOTS 3000 +#define POLYTEXT16_CACHE_THRESHOLD 4 +#define POLYTEXT16_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class PolyText16Message : public Message +{ + friend class PolyText16Store; + + public: + + PolyText16Message() + { + } + + ~PolyText16Message() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int drawable; + unsigned int gcontext; + + unsigned short x; + unsigned short y; +}; + +class PolyText16Store : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + PolyText16Store() : MessageStore() + { + enableCache = POLYTEXT16_ENABLE_CACHE; + enableData = POLYTEXT16_ENABLE_DATA; + enableSplit = POLYTEXT16_ENABLE_SPLIT; + enableCompress = POLYTEXT16_ENABLE_COMPRESS; + + dataLimit = POLYTEXT16_DATA_LIMIT; + dataOffset = POLYTEXT16_DATA_OFFSET; + + cacheSlots = POLYTEXT16_CACHE_SLOTS; + cacheThreshold = POLYTEXT16_CACHE_THRESHOLD; + cacheLowerThreshold = POLYTEXT16_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~PolyText16Store() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "PolyText16"; + } + + virtual unsigned char opcode() const + { + return X_PolyText16; + } + + virtual unsigned int storage() const + { + return sizeof(PolyText16Message); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new PolyText16Message(); + } + + virtual Message *create(const Message &message) const + { + return new PolyText16Message((const PolyText16Message &) message); + } + + virtual void destroy(Message *message) const + { + delete (PolyText16Message *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PolyText16_H */ diff --git a/nxcomp/src/PolyText8.cpp b/nxcomp/src/PolyText8.cpp new file mode 100644 index 000000000..61fef5a4f --- /dev/null +++ b/nxcomp/src/PolyText8.cpp @@ -0,0 +1,310 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PolyText8.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int PolyText8Store::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyText8Message *polyText8 = (PolyText8Message *) message; + + // + // Here is the fingerprint. + // + + polyText8 -> drawable = GetULONG(buffer + 4, bigEndian); + polyText8 -> gcontext = GetULONG(buffer + 8, bigEndian); + + polyText8 -> x = GetUINT(buffer + 12, bigEndian); + polyText8 -> y = GetUINT(buffer + 14, bigEndian); + + // + // Clean up padding bytes. + // + + #ifdef DUMP + + DumpData(buffer, size); + + *logofs << "\n\n" << logofs_flush; + + #endif + + if ((int) size > dataOffset) + { + int length; + int current; + int delta; + int item; + + unsigned int nitem; + + unsigned char *pad = NULL; + unsigned char *end = NULL; + + delta = 1; + nitem = 0; + + #ifdef DUMP + *logofs << name() << " Size " << size << ".\n" << logofs_flush; + #endif + + // + // Data is a list of TextItem where element + // can be a string or a font shift. + // + + current = POLYTEXT8_DATA_OFFSET; + length = POLYTEXT8_DATA_OFFSET; + + do + { + #ifdef DUMP + *logofs << name() << " Current " << current << ".\n" << logofs_flush; + #endif + + item = GetUINT(buffer + length , bigEndian); + + if (item < 255) + { + // + // Text element. Number represents + // the 'Length of string' field. + // + + length += (item + delta + 1); + + nitem++; + } + else if (item == 255) + { + // + // Element is a font shift. + // + + length += 5; + + nitem++; + } + + #ifdef DUMP + *logofs << name() << " Item " << item << ".\n" << logofs_flush; + #endif + + current += length; + } + while(current < (int) size && item != 0); + + + #ifdef DUMP + *logofs << name() << " Final length " << length << ".\n" << logofs_flush; + #endif + + end = ((unsigned char *) buffer) + size; + + pad = ((unsigned char *) buffer) + length; + + for (; pad < end && nitem >= 1; pad++) + { + #ifdef DUMP + *logofs << name() << " Padding " << " .\n" << logofs_flush; + #endif + + *pad = 0; + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PolyText8Store::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PolyText8Message *polyText8 = (PolyText8Message *) message; + + // + // Fill all the message's fields. + // + + PutULONG(polyText8 -> drawable, buffer + 4, bigEndian); + PutULONG(polyText8 -> gcontext, buffer + 8, bigEndian); + + PutUINT(polyText8 -> x, buffer + 12, bigEndian); + PutUINT(polyText8 -> y, buffer + 14, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PolyText8Store::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PolyText8Message *polyText8 = (PolyText8Message *) message; + + *logofs << name() << ": Identity drawable " << polyText8 -> drawable + << ", gcontext " << polyText8 -> gcontext << ", x " << polyText8 -> x + << ", y " << polyText8 -> y << ", size " << polyText8 -> size_ + << ".\n"; + + #endif +} + +void PolyText8Store::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +} + +void PolyText8Store::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + PolyText8Message *polyText8 = (PolyText8Message *) message; + PolyText8Message *cachedPolyText8 = (PolyText8Message *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyText8 -> drawable + << " as " << "drawable" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyText8 -> drawable, clientCache -> drawableCache); + + cachedPolyText8 -> drawable = polyText8 -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyText8 -> gcontext + << " as " << "gcontext" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(polyText8 -> gcontext, clientCache -> gcCache); + + cachedPolyText8 -> gcontext = polyText8 -> gcontext; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyText8 -> x + << " as " << "x" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_x = polyText8 -> x - cachedPolyText8 -> x; + + encodeBuffer.encodeCachedValue(diff_x, 16, + clientCache -> polyTextCacheX); + + cachedPolyText8 -> x = polyText8 -> x; + + #ifdef TEST + *logofs << name() << ": Encoding value " << polyText8 -> y + << " as " << "y" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_y = polyText8 -> y - cachedPolyText8 -> y; + + encodeBuffer.encodeCachedValue(diff_y, 16, + clientCache -> polyTextCacheY); + + cachedPolyText8 -> y = polyText8 -> y; +} + +void PolyText8Store::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + PolyText8Message *polyText8 = (PolyText8Message *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + polyText8 -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyText8 -> drawable + << " as " << "drawable" << " field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + polyText8 -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyText8 -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> polyTextCacheX); + + polyText8 -> x += value; + polyText8 -> x &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyText8 -> x + << " as x field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> polyTextCacheY); + + polyText8 -> y += value; + polyText8 -> y &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << polyText8 -> y + << " as y field.\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/PolyText8.h b/nxcomp/src/PolyText8.h new file mode 100644 index 000000000..3d5ff533a --- /dev/null +++ b/nxcomp/src/PolyText8.h @@ -0,0 +1,188 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PolyText8_H +#define PolyText8_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define POLYTEXT8_ENABLE_CACHE 1 +#define POLYTEXT8_ENABLE_DATA 0 +#define POLYTEXT8_ENABLE_SPLIT 0 +#define POLYTEXT8_ENABLE_COMPRESS 0 + +#define POLYTEXT8_DATA_LIMIT 380 +#define POLYTEXT8_DATA_OFFSET 16 + +#define POLYTEXT8_CACHE_SLOTS 3000 +#define POLYTEXT8_CACHE_THRESHOLD 5 +#define POLYTEXT8_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class PolyText8Message : public Message +{ + friend class PolyText8Store; + + public: + + PolyText8Message() + { + } + + ~PolyText8Message() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int drawable; + unsigned int gcontext; + + unsigned short x; + unsigned short y; +}; + +class PolyText8Store : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + PolyText8Store() : MessageStore() + { + enableCache = POLYTEXT8_ENABLE_CACHE; + enableData = POLYTEXT8_ENABLE_DATA; + enableSplit = POLYTEXT8_ENABLE_SPLIT; + enableCompress = POLYTEXT8_ENABLE_COMPRESS; + + dataLimit = POLYTEXT8_DATA_LIMIT; + dataOffset = POLYTEXT8_DATA_OFFSET; + + cacheSlots = POLYTEXT8_CACHE_SLOTS; + cacheThreshold = POLYTEXT8_CACHE_THRESHOLD; + cacheLowerThreshold = POLYTEXT8_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~PolyText8Store() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "PolyText8"; + } + + virtual unsigned char opcode() const + { + return X_PolyText8; + } + + virtual unsigned int storage() const + { + return sizeof(PolyText8Message); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new PolyText8Message(); + } + + virtual Message *create(const Message &message) const + { + return new PolyText8Message((const PolyText8Message &) message); + } + + virtual void destroy(Message *message) const + { + delete (PolyText8Message *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PolyText8_H */ diff --git a/nxcomp/src/Proxy.cpp b/nxcomp/src/Proxy.cpp new file mode 100644 index 000000000..72b2cee21 --- /dev/null +++ b/nxcomp/src/Proxy.cpp @@ -0,0 +1,6529 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef ANDROID +#include +#include +#include +#endif + +#include "Misc.h" + +#if defined(__CYGWIN32__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun) +#include +#endif + +#ifndef ANDROID +#include +#include +#include +#endif + +#include "NXalert.h" +#include "NXvars.h" + +#include "Proxy.h" + +#include "Socket.h" +#include "Channel.h" +#include "Statistics.h" + +#include "ClientChannel.h" +#include "ServerChannel.h" +#include "GenericChannel.h" +#include "ChannelEndPoint.h" + +// +// We need to adjust some values related +// to these messages at the time the mes- +// sage stores are reconfigured. +// + +#include "PutImage.h" +#include "ChangeGC.h" +#include "PolyFillRectangle.h" +#include "PutPackedImage.h" + +// +// This is from the main loop. +// + +extern void CleanupListeners(); + +extern int HandleChild(int); + +// +// Default size of string buffers. +// + +#define DEFAULT_STRING_LENGTH 512 + +// +// Set the verbosity level. You also need +// to define DUMP in Misc.cpp if DUMP is +// defined here. +// + +#define WARNING +#define PANIC +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Log the important tracepoints related +// to writing packets to the peer proxy. +// + +#undef FLUSH + +// +// Log the operations related to splits. +// + +#undef SPLIT + +// +// Log the operations related to sending +// and receiving the control tokens. +// + +#undef TOKEN + +// +// Log the operations related to setting +// the token limits. +// + +#undef LIMIT + +// +// Log a warning if no data is written by +// the proxy within a timeout. +// + +#undef TIME + +// +// Log the operation related to generating +// the ping message at idle time. +// + +#undef PING + +Proxy::Proxy(int fd) + + : transport_(new ProxyTransport(fd)), fd_(fd), readBuffer_(transport_) +{ + for (int channelId = 0; + channelId < CONNECTIONS_LIMIT; + channelId++) + { + channels_[channelId] = NULL; + transports_[channelId] = NULL; + congestions_[channelId] = 0; + + fdMap_[channelId] = nothing; + channelMap_[channelId] = nothing; + slavePidMap_[channelId] = nothing; + } + + inputChannel_ = nothing; + outputChannel_ = nothing; + + controlLength_ = 0; + + operation_ = operation_in_negotiation; + + draining_ = 0; + priority_ = 0; + finish_ = 0; + shutdown_ = 0; + congestion_ = 0; + + timer_ = 0; + alert_ = 0; + + agent_ = nothing; + + // + // Set null timeouts. This will require + // a new link configuration. + // + + timeouts_.split = 0; + timeouts_.motion = 0; + + timeouts_.readTs = getTimestamp(); + timeouts_.writeTs = getTimestamp(); + + timeouts_.loopTs = getTimestamp(); + timeouts_.pingTs = getTimestamp(); + timeouts_.alertTs = nullTimestamp(); + timeouts_.loadTs = nullTimestamp(); + + timeouts_.splitTs = nullTimestamp(); + timeouts_.motionTs = nullTimestamp(); + + // + // Initialize the token counters. This + // will require a new link configuration. + // + + for (int i = token_control; i <= token_data; i++) + { + tokens_[i].size = 0; + tokens_[i].limit = 0; + + tokens_[i].bytes = 0; + tokens_[i].remaining = 0; + } + + tokens_[token_control].request = code_control_token_request; + tokens_[token_control].reply = code_control_token_reply; + tokens_[token_control].type = token_control; + + tokens_[token_split].request = code_split_token_request; + tokens_[token_split].reply = code_split_token_reply; + tokens_[token_split].type = token_split; + + tokens_[token_data].request = code_data_token_request; + tokens_[token_data].reply = code_data_token_reply; + tokens_[token_data].type = token_data; + + currentStatistics_ = NULL; + + // + // Create compressor and decompressor + // for image and data payload. + // + + compressor_ = new StaticCompressor(control -> LocalDataCompressionLevel, + control -> LocalDataCompressionThreshold); + + // + // Create object storing NX specific + // opcodes. + // + + opcodeStore_ = new OpcodeStore(); + + // + // Create the message stores. + // + + clientStore_ = new ClientStore(compressor_); + serverStore_ = new ServerStore(compressor_); + + clientCache_ = new ClientCache(); + serverCache_ = new ServerCache(); + + if (clientCache_ == NULL || serverCache_ == NULL) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Failed to create the channel cache.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed to create the channel cache.\n"; + + HandleCleanup(); + } + + // + // Prepare for image decompression. + // + + UnpackInit(); + + #ifdef DEBUG + *logofs << "Proxy: Created new object at " << this + << ".\n" << logofs_flush; + #endif +} + +Proxy::~Proxy() +{ + for (int channelId = 0; + channelId < CONNECTIONS_LIMIT; + channelId++) + { + if (channels_[channelId] != NULL) + { + deallocateTransport(channelId); + + delete channels_[channelId]; + channels_[channelId] = NULL; + } + } + + // + // Kill all active slave channel children, and + // give them 5 seconds to exit nicely. + + #ifdef DEBUG + *logofs << "Proxy: Killing active slaves" << endl; + #endif + + int slave_count = 999; + int loop_count = 0; + + while(slave_count > 0 && loop_count < 50) + { + slave_count = 0; + + for (int channelId = 0; channelId 1) { + slave_count++; + + #ifdef DEBUG + *logofs << "Proxy: Active slave with pid " << pid << logofs_flush; + #endif + + if ( loop_count == 0 ) + { + #ifdef DEBUG + *logofs << "Proxy: Sending SIGTERM to " << pid << logofs_flush; + #endif + kill(pid, SIGTERM); + } + else if ( loop_count == 25 ) + { + #ifdef DEBUG + *logofs << "Proxy: Sending SIGKILL to " << pid << logofs_flush; + #endif + kill(pid, SIGKILL); + } + + if (HandleChild(pid)) + { + #ifdef DEBUG + *logofs << "Proxy: Slave " << pid << " terminated" << logofs_flush; + #endif + slavePidMap_[channelId] = nothing; + } + } + } + + if ( slave_count > 0 ) + { + cerr << "Proxy: Error: Failed to kill all slave channel processes. " << slave_count << " processes still remaining." << endl; + } + + usleep(200000); + loop_count++; + } + + delete transport_; + delete compressor_; + + // + // Delete storage shared among channels. + // + + delete opcodeStore_; + + delete clientStore_; + delete serverStore_; + + delete clientCache_; + delete serverCache_; + + // + // Get rid of the image decompression + // resources. + // + + UnpackDestroy(); + + #ifdef DEBUG + *logofs << "Proxy: Deleted proxy object at " << this + << ".\n" << logofs_flush; + #endif +} + +int Proxy::setOperational() +{ + #ifdef TEST + *logofs << "Proxy: Entering operational mode.\n" + << logofs_flush; + #endif + + operation_ = operation_in_messages; + + return 1; +} + +int Proxy::setReadDescriptors(fd_set *fdSet, int &fdMax, T_timestamp &tsMax) +{ + // + // Set the initial timeout to the time of + // the next ping. If the congestion count + // is greater than zero, anyway, use a + // shorter timeout to force a congestion + // update. + // + + if (agent_ != nothing && congestions_[agent_] == 0 && + statistics -> getCongestionInFrame() >= 1 && + tokens_[token_control].remaining >= + (tokens_[token_control].limit - 1)) + { + setMinTimestamp(tsMax, control -> IdleTimeout); + + #ifdef TEST + *logofs << "Proxy: Initial timeout is " << tsMax.tv_sec + << " S and " << (double) tsMax.tv_usec / + 1000 << " Ms with congestion " + << statistics -> getCongestionInFrame() + << ".\n" << logofs_flush; + #endif + } + else + { + setMinTimestamp(tsMax, control -> PingTimeout); + + #ifdef TEST + *logofs << "Proxy: Initial timeout is " << tsMax.tv_sec + << " S and " << (double) tsMax.tv_usec / + 1000 << " Ms.\n" << logofs_flush; + #endif + } + + int fd = -1; + + if (isTimeToRead() == 1) + { + // + // If we don't have split tokens available + // don't set the timeout. + // + + if (tokens_[token_split].remaining > 0 && + isTimestamp(timeouts_.splitTs) == 1) + { + int diffTs = getTimeToNextSplit(); + + #if defined(TEST) || defined(INFO) || \ + defined(FLUSH) || defined(SPLIT) + + if (diffTimestamp(timeouts_.splitTs, + getTimestamp()) > timeouts_.split) + { + *logofs << "Proxy: FLUSH! SPLIT! WARNING! Running with " + << diffTimestamp(timeouts_.splitTs, getTimestamp()) + << " Ms elapsed since the last split.\n" + << logofs_flush; + } + + *logofs << "Proxy: FLUSH! SPLIT! Requesting timeout of " + << diffTs << " Ms as there are splits to send.\n" + << logofs_flush; + + #endif + + setMinTimestamp(tsMax, diffTs); + } + #if defined(TEST) || defined(INFO) + else if (isTimestamp(timeouts_.splitTs) == 1) + { + *logofs << "Proxy: WARNING! Not requesting a split " + << "timeout with " << tokens_[token_split].remaining + << " split tokens remaining.\n" << logofs_flush; + } + #endif + + // + // Loop through the valid channels and set + // the descriptors selected for read and + // the timeout. + // + + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] == NULL) + { + continue; + } + + fd = getFd(channelId); + + if (channels_[channelId] -> getFinish() == 0 && + (channels_[channelId] -> getType() == channel_x11 || + tokens_[token_data].remaining > 0) && + congestions_[channelId] == 0) + { + FD_SET(fd, fdSet); + + if (fd >= fdMax) + { + fdMax = fd + 1; + } + + #ifdef TEST + *logofs << "Proxy: Descriptor FD#" << fd + << " selected for read with buffer length " + << transports_[channelId] -> length() + << ".\n" << logofs_flush; + #endif + + // + // Wakeup the proxy if there are motion + // events to flush. + // + + if (isTimestamp(timeouts_.motionTs) == 1) + { + int diffTs = getTimeToNextMotion(); + + #if defined(TEST) || defined(INFO) + + if (diffTimestamp(timeouts_.motionTs, + getTimestamp()) > timeouts_.motion) + { + *logofs << "Proxy: FLUSH! WARNING! Running with " + << diffTimestamp(timeouts_.motionTs, getTimestamp()) + << " Ms elapsed since the last motion.\n" + << logofs_flush; + } + + *logofs << "Proxy: FLUSH! Requesting timeout of " + << diffTs << " Ms as FD#" << fd << " has motion " + << "events to send.\n" << logofs_flush; + + #endif + + setMinTimestamp(tsMax, diffTs); + } + } + #if defined(TEST) || defined(INFO) + else + { + if (channels_[channelId] -> getType() != channel_x11 && + tokens_[token_data].remaining <= 0) + { + *logofs << "Proxy: WARNING! Descriptor FD#" << fd + << " not selected for read with " + << tokens_[token_data].remaining << " data " + << "tokens remaining.\n" << logofs_flush; + } + } + #endif + } + } + #if defined(TEST) || defined(INFO) + else + { + *logofs << "Proxy: WARNING! Disabled reading from channels.\n" + << logofs_flush; + + *logofs << "Proxy: WARNING! Congestion is " << congestion_ + << " pending " << transport_ -> pending() << " blocked " + << transport_ -> blocked() << " length " << transport_ -> + length() << ".\n" << logofs_flush; + } + #endif + + // + // Include the proxy descriptor. + // + + FD_SET(fd_, fdSet); + + if (fd_ >= fdMax) + { + fdMax = fd_ + 1; + } + + #ifdef TEST + *logofs << "Proxy: Proxy descriptor FD#" << fd_ + << " selected for read with buffer length " + << transport_ -> length() << ".\n" + << logofs_flush; + #endif + + return 1; +} + +// +// Add to the mask the file descriptors of all +// X connections to write to. +// + +int Proxy::setWriteDescriptors(fd_set *fdSet, int &fdMax, T_timestamp &tsMax) +{ + int fd = -1; + + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] != NULL) + { + fd = getFd(channelId); + + if (transports_[channelId] -> length() > 0) + { + FD_SET(fd, fdSet); + + #ifdef TEST + *logofs << "Proxy: Descriptor FD#" << fd << " selected " + << "for write with blocked " << transports_[channelId] -> + blocked() << " and length " << transports_[channelId] -> + length() << ".\n" << logofs_flush; + #endif + + if (fd >= fdMax) + { + fdMax = fd + 1; + } + } + #ifdef TEST + else + { + *logofs << "Proxy: Descriptor FD#" << fd << " not selected " + << "for write with blocked " << transports_[channelId] -> + blocked() << " and length " << transports_[channelId] -> + length() << ".\n" << logofs_flush; + } + #endif + + #if defined(TEST) || defined(INFO) + + if (transports_[channelId] -> getType() != + transport_agent && transports_[channelId] -> + length() > 0 && transports_[channelId] -> + blocked() != 1) + { + *logofs << "Proxy: PANIC! Descriptor FD#" << fd + << " has data to write but blocked flag is " + << transports_[channelId] -> blocked() + << ".\n" << logofs_flush; + + cerr << "Error" << ": Descriptor FD#" << fd + << " has data to write but blocked flag is " + << transports_[channelId] -> blocked() + << ".\n"; + + HandleCleanup(); + } + + #endif + } + } + + // + // Check if the proxy transport has data + // from a previous blocking write. + // + + if (transport_ -> blocked() == 1) + { + FD_SET(fd_, fdSet); + + #ifdef TEST + *logofs << "Proxy: Proxy descriptor FD#" + << fd_ << " selected for write. Blocked is " + << transport_ -> blocked() << " length is " + << transport_ -> length() << ".\n" + << logofs_flush; + #endif + + if (fd_ >= fdMax) + { + fdMax = fd_ + 1; + } + } + #ifdef TEST + else + { + *logofs << "Proxy: Proxy descriptor FD#" + << fd_ << " not selected for write. Blocked is " + << transport_ -> blocked() << " length is " + << transport_ -> length() << ".\n" + << logofs_flush; + } + #endif + + // + // We are entering the main select. Save + // the timestamp of the last loop so that + // we can detect the clock drifts. + // + + timeouts_.loopTs = getTimestamp(); + + return 1; +} + +int Proxy::getChannels(T_channel_type type) +{ + int channels = 0; + + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] != NULL && + (type == channel_none || + type == channels_[channelId] -> + getType())) + { + channels++; + } + } + + return channels; +} + +T_channel_type Proxy::getType(int fd) +{ + int channelId = getChannel(fd); + + if (channelId < 0 || channels_[channelId] == NULL) + { + return channel_none; + } + + return channels_[channelId] -> getType(); +} + +const char *Proxy::getTypeName(T_channel_type type) +{ + switch (type) + { + case channel_x11: + { + return "X"; + } + case channel_cups: + { + return "CUPS"; + } + case channel_smb: + { + return "SMB"; + } + case channel_media: + { + return "media"; + } + case channel_http: + { + return "HTTP"; + } + case channel_font: + { + return "font"; + } + case channel_slave: + { + return "slave"; + } + default: + { + return "unknown"; + } + } +} + +const char *Proxy::getComputerName() +{ + // + // Strangely enough, under some Windows OSes SMB + // service doesn't bind to localhost. Fall back + // to localhost if can't find computer name in + // the environment. In future we should try to + // bind to localhost and then try the other IPs. + // + + const char *hostname = NULL; + + #ifdef __CYGWIN32__ + + hostname = getenv("COMPUTERNAME"); + + #endif + + if (hostname == NULL) + { + hostname = "localhost"; + } + + return hostname; +} + +// +// Handle data from channels selected for read. +// + +int Proxy::handleRead(int &resultFds, fd_set &readSet) +{ + #ifdef DEBUG + *logofs << "Proxy: Checking descriptors selected for read.\n" + << logofs_flush; + #endif + + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + #ifdef DEBUG + *logofs << "Proxy: Looping with current channel " + << *j << ".\n" << logofs_flush; + #endif + + int fd = getFd(*j); + + if (fd >= 0 && resultFds > 0 && FD_ISSET(fd, &readSet)) + { + #ifdef DEBUG + *logofs << "Proxy: Going to read messages from FD#" + << fd << ".\n" << logofs_flush; + #endif + + int result = handleRead(fd); + + if (result < 0) + { + #ifdef TEST + *logofs << "Proxy: Failure reading messages from FD#" + << fd << ".\n" << logofs_flush; + #endif + + return -1; + } + + #ifdef DEBUG + *logofs << "Proxy: Clearing the read descriptor " + << "for FD#" << fd << ".\n" << logofs_flush; + #endif + + FD_CLR(fd, &readSet); + + resultFds--; + } + } + + if (resultFds > 0 && FD_ISSET(fd_, &readSet)) + { + #ifdef DEBUG + *logofs << "Proxy: Going to read messages from " + << "proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + if (handleRead() < 0) + { + #ifdef TEST + *logofs << "Proxy: Failure reading from proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + return -1; + } + + #ifdef DEBUG + *logofs << "Proxy: Clearing the read descriptor " + << "for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + FD_CLR(fd_, &readSet); + + resultFds--; + } + + return 1; +} + +// +// Perform flush on descriptors selected for write. +// + +int Proxy::handleFlush(int &resultFds, fd_set &writeSet) +{ + #ifdef DEBUG + *logofs << "Proxy: Checking descriptors selected for write.\n" + << logofs_flush; + #endif + + if (resultFds > 0 && FD_ISSET(fd_, &writeSet)) + { + #ifdef TEST + *logofs << "Proxy: FLUSH! Proxy descriptor FD#" << fd_ + << " reported to be writable.\n" + << logofs_flush; + #endif + + if (handleFlush() < 0) + { + #ifdef TEST + *logofs << "Proxy: Failure flushing the writable " + << "proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + return -1; + } + + #ifdef DEBUG + *logofs << "Proxy: Clearing the write descriptor " + << "for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + FD_CLR(fd_, &writeSet); + + resultFds--; + } + + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + resultFds > 0 && j != channelList.end(); j++) + { + #ifdef DEBUG + *logofs << "Proxy: Looping with current channel " + << *j << ".\n" << logofs_flush; + #endif + + int fd = getFd(*j); + + if (fd >= 0 && FD_ISSET(fd, &writeSet)) + { + #ifdef TEST + *logofs << "Proxy: X descriptor FD#" << fd + << " reported to be writable.\n" + << logofs_flush; + #endif + + // + // It can happen that, in handling reads, we + // have destroyed the buffer associated to a + // closed socket, so don't complain about + // the errors. + // + + handleFlush(fd); + + // + // Clear the descriptor from the mask so + // we don't confuse the agent if it's + // not checking only its own descriptors. + // + + #ifdef DEBUG + *logofs << "Proxy: Clearing the write descriptor " + << "for FD#" << fd << ".\n" + << logofs_flush; + #endif + + FD_CLR(fd, &writeSet); + + resultFds--; + } + } + + return 1; +} + +int Proxy::handleRead() +{ + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Decoding data from proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + // + // Decode all the available messages from + // the remote proxy until is not possible + // to read more. + // + + for (;;) + { + int result = readBuffer_.readMessage(); + + #if defined(TEST) || defined(DEBUG) || defined(INFO) + *logofs << "Proxy: Read result on proxy FD#" << fd_ + << " is " << result << ".\n" + << logofs_flush; + #endif + + if (result < 0) + { + if (shutdown_ == 0) + { + if (finish_ == 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Failure reading from the " + << "peer proxy on FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure reading from the " + << "peer proxy.\n"; + } + } + #ifdef TEST + else + { + *logofs << "Proxy: Closure of the proxy link detected " + << "after clean shutdown.\n" << logofs_flush; + } + #endif + + priority_ = 0; + finish_ = 1; + congestion_ = 0; + + return -1; + } + else if (result == 0) + { + #if defined(TEST) || defined(DEBUG) || defined(INFO) + *logofs << "Proxy: No data read from proxy FD#" + << fd_ << "\n" << logofs_flush; + #endif + + return 0; + } + + // + // We read some data from the remote. If we set + // the congestion flag because we couldn't read + // before the timeout and have tokens available, + // then reset the congestion flag. + // + + if (congestion_ == 1 && + tokens_[token_control].remaining > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Exiting congestion due to " + << "proxy data with " << tokens_[token_control].remaining + << " tokens.\n" << logofs_flush; + #endif + + congestion_ = 0; + } + + // + // Set the timestamp of the last read + // operation from the remote proxy and + // enable again showing the 'no data + // received' dialog at the next timeout. + // + + timeouts_.readTs = getTimestamp(); + + if (alert_ != 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Displacing the dialog " + << "for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + HandleAlert(DISPLACE_MESSAGE_ALERT, 1); + } + + timeouts_.alertTs = nullTimestamp(); + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Getting messages from proxy FD#" << fd_ + << " with " << readBuffer_.getLength() << " bytes " + << "in the read buffer.\n" << logofs_flush; + #endif + + unsigned int controlLength; + unsigned int dataLength; + + const unsigned char *message; + + while ((message = readBuffer_.getMessage(controlLength, dataLength)) != NULL) + { + statistics -> addFrameIn(); + + if (controlLength == 3 && *message == 0 && + *(message + 1) < code_last_tag) + { + if (handleControlFromProxy(message) < 0) + { + return -1; + } + } + else if (operation_ == operation_in_messages) + { + int channelId = inputChannel_; + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Identified message of " << dataLength + << " bytes for FD#" << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + if (channelId >= 0 && channelId < CONNECTIONS_LIMIT && + channels_[channelId] != NULL) + { + int finish = channels_[channelId] -> getFinish(); + + #ifdef WARNING + + if (finish == 1) + { + *logofs << "Proxy: WARNING! Handling data for finishing " + << "FD#" << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + } + + #endif + + // + // We need to decode all the data to preserve + // the consistency of the cache, so can't re- + // turn as soon as the first error is encount- + // ered. Check if this is the first time that + // the failure is detected. + // + + int result = channels_[channelId] -> handleWrite(message, dataLength); + + if (result < 0 && finish == 0) + { + #ifdef TEST + *logofs << "Proxy: Failed to write proxy data to FD#" + << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + if (handleFinish(channelId) < 0) + { + return -1; + } + } + + // + // Check if we have splits or motion + // events to send. + // + + setSplitTimeout(channelId); + setMotionTimeout(channelId); + } + #ifdef WARNING + else + { + *logofs << "Proxy: WARNING! Received data for " + << "invalid channel ID#" << channelId + << ".\n" << logofs_flush; + } + #endif + } + else if (operation_ == operation_in_statistics) + { + #ifdef TEST + *logofs << "Proxy: Received statistics data from remote proxy.\n" + << logofs_flush; + #endif + + if (handleStatisticsFromProxy(message, dataLength) < 0) + { + return -1; + } + + operation_ = operation_in_messages; + } + else if (operation_ == operation_in_negotiation) + { + #ifdef TEST + *logofs << "Proxy: Received new negotiation data from remote proxy.\n" + << logofs_flush; + #endif + + if (handleNegotiationFromProxy(message, dataLength) < 0) + { + return -1; + } + } + + // + // if (controlLength == 3 && *message == 0 && ...) ... + // else if (operation_ == operation_in_statistics) ... + // else if (operation_ == operation_in_messages) ... + // else if (operation_ == operation_in_negotiation) ... + // else ... + // + + else + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Unrecognized message received on proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unrecognized message received on proxy FD#" + << fd_ << ".\n"; + + return -1; + } + + } // while ((message = readBuffer_.getMessage(controlLength, dataLength)) != NULL) ... + + // + // Reset the read buffer. + // + + readBuffer_.fullReset(); + + // + // Give up if no data is readable. + // + + if (transport_ -> readable() == 0) + { + break; + } + + } // End of for (;;) ... + + return 1; +} + +int Proxy::handleControlFromProxy(const unsigned char *message) +{ + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Received message '" << DumpControl(*(message + 1)) + << "' at " << strMsTimestamp() << " with data ID#" + << (int) *(message + 2) << ".\n" << logofs_flush; + #endif + + T_channel_type channelType = channel_none; + + switch (*(message + 1)) + { + case code_switch_connection: + { + int channelId = *(message + 2); + + // + // If channel is invalid further messages will + // be ignored. The acknowledged shutdown of + // channels should prevent this. + // + + inputChannel_ = channelId; + + break; + } + case code_begin_congestion: + { + // + // Set the congestion state for the + // channel reported by the remote. + // + + int channelId = *(message + 2); + + if (channels_[channelId] != NULL) + { + congestions_[channelId] = 1; + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Received a begin congestion " + << "for channel id ID#" << channelId + << ".\n" << logofs_flush; + #endif + + if (channelId == agent_ && congestions_[agent_] != 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Forcing an update of the congestion " + << "counter with agent congested.\n" + << logofs_flush; + #endif + + statistics -> updateCongestion(-tokens_[token_control].remaining, + tokens_[token_control].limit); + } + } + #ifdef WARNING + else + { + *logofs << "Proxy: WARNING! Received a begin congestion " + << "for invalid channel id ID#" << channelId + << ".\n" << logofs_flush; + } + #endif + + break; + } + case code_end_congestion: + { + // + // Attend again to the channel. + // + + int channelId = *(message + 2); + + if (channels_[channelId] != NULL) + { + congestions_[channelId] = 0; + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Received an end congestion " + << "for channel id ID#" << channelId + << ".\n" << logofs_flush; + #endif + + if (channelId == agent_ && congestions_[agent_] != 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Forcing an update of the congestion " + << "counter with agent decongested.\n" + << logofs_flush; + #endif + + statistics -> updateCongestion(tokens_[token_control].remaining, + tokens_[token_control].limit); + } + } + #ifdef WARNING + else + { + *logofs << "Proxy: WARNING! Received an end congestion " + << "for invalid channel id ID#" << channelId + << ".\n" << logofs_flush; + } + #endif + + break; + } + case code_control_token_request: + { + T_proxy_token &token = tokens_[token_control]; + + if (handleTokenFromProxy(token, *(message + 2)) < 0) + { + return -1; + } + + break; + } + case code_split_token_request: + { + T_proxy_token &token = tokens_[token_split]; + + if (handleTokenFromProxy(token, *(message + 2)) < 0) + { + return -1; + } + + break; + } + case code_data_token_request: + { + T_proxy_token &token = tokens_[token_data]; + + if (handleTokenFromProxy(token, *(message + 2)) < 0) + { + return -1; + } + + break; + } + case code_control_token_reply: + { + T_proxy_token &token = tokens_[token_control]; + + if (handleTokenReplyFromProxy(token, *(message + 2)) < 0) + { + return -1; + } + + break; + } + case code_split_token_reply: + { + T_proxy_token &token = tokens_[token_split]; + + if (handleTokenReplyFromProxy(token, *(message + 2)) < 0) + { + return -1; + } + + break; + } + case code_data_token_reply: + { + T_proxy_token &token = tokens_[token_data]; + + if (handleTokenReplyFromProxy(token, *(message + 2)) < 0) + { + return -1; + } + + break; + } + case code_new_x_connection: + { + // + // Opening the channel is handled later. + // + + channelType = channel_x11; + + break; + } + case code_new_cups_connection: + { + channelType = channel_cups; + + break; + } + case code_new_aux_connection: + { + // + // Starting from version 1.5.0 we create real X + // connections for the keyboard channel. We need + // to refuse old auxiliary X connections because + // they would be unable to leverage the new fake + // authorization cookie. + // + + #ifdef WARNING + *logofs << "Proxy: WARNING! Can't open outdated auxiliary X " + << "channel for code " << *(message + 1) << ".\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Can't open outdated auxiliary X " + << "channel for code " << *(message + 1) << ".\n"; + + if (handleControl(code_drop_connection, *(message + 2)) < 0) + { + return -1; + } + + break; + } + case code_new_smb_connection: + { + channelType = channel_smb; + + break; + } + case code_new_media_connection: + { + channelType = channel_media; + + break; + } + case code_new_http_connection: + { + channelType = channel_http; + + break; + } + case code_new_font_connection: + { + channelType = channel_font; + + break; + } + case code_new_slave_connection: + { + channelType = channel_slave; + + break; + } + case code_drop_connection: + { + int channelId = *(message + 2); + + if (channelId >= 0 && channelId < CONNECTIONS_LIMIT && + channels_[channelId] != NULL) + { + handleDropFromProxy(channelId); + } + #ifdef WARNING + else + { + *logofs << "Proxy: WARNING! Received a drop message " + << "for invalid channel id ID#" << channelId + << ".\n" << logofs_flush; + } + #endif + + break; + } + case code_finish_connection: + { + int channelId = *(message + 2); + + if (channelId >= 0 && channelId < CONNECTIONS_LIMIT && + channels_[channelId] != NULL) + { + // + // Force the finish state on the channel. + // We can receive this message while in + // the read loop, so we only mark the + // channel for deletion. + // + + #ifdef TEST + *logofs << "Proxy: Received a finish message for FD#" + << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + handleFinishFromProxy(channelId); + } + #ifdef WARNING + else + { + *logofs << "Proxy: WARNING! Received a finish message " + << "for invalid channel id ID#" << channelId + << ".\n" << logofs_flush; + } + #endif + + break; + } + case code_finish_listeners: + { + // + // This is from the main loop. + // + + #ifdef TEST + *logofs << "Proxy: Closing down all local listeners.\n" + << logofs_flush; + #endif + + CleanupListeners(); + + finish_ = 1; + + break; + } + case code_reset_request: + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Proxy reset not supported " + << "in this version.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Proxy reset not supported " + << "in this version.\n"; + + HandleCleanup(); + } + case code_shutdown_request: + { + // + // Time to rest in peace. + // + + shutdown_ = 1; + + break; + } + case code_load_request: + { + if (handleLoadFromProxy() < 0) + { + return -1; + } + + break; + } + case code_save_request: + { + // + // Don't abort the connection + // if can't write to disk. + // + + handleSaveFromProxy(); + + break; + } + case code_statistics_request: + { + int type = *(message + 2); + + if (handleStatisticsFromProxy(type) < 0) + { + return -1; + } + + break; + } + case code_statistics_reply: + { + operation_ = operation_in_statistics; + + break; + } + case code_alert_request: + { + HandleAlert(*(message + 2), 1); + + break; + } + case code_sync_request: + { + int channelId = *(message + 2); + + if (handleSyncFromProxy(channelId) < 0) + { + return -1; + } + + break; + } + case code_sync_reply: + { + // + // We are not the one that issued + // the request. + // + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: PANIC! Received an unexpected " + << "synchronization reply.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Received an unexpected " + << "synchronization reply.\n"; + + HandleCleanup(); + } + default: + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Received bad control message number " + << (unsigned int) *(message + 1) << " with attribute " + << (unsigned int) *(message + 2) << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Received bad control message number " + << (unsigned int) *(message + 1) << " with attribute " + << (unsigned int) *(message + 2) << ".\n"; + + HandleCleanup(); + } + + } // End of switch (*(message + 1)) ... + + if (channelType == channel_none) + { + return 1; + } + + // + // Handle the channel allocation that we + // left from the main switch case. + // + + int channelId = *(message + 2); + + // + // Check if the channel has been dropped. + // + + if (channels_[channelId] != NULL && + (channels_[channelId] -> getDrop() == 1 || + channels_[channelId] -> getClosing() == 1)) + { + #ifdef TEST + *logofs << "Proxy: Dropping the descriptor FD#" + << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + handleDrop(channelId); + } + + // + // Check if the channel is in the valid + // range. + // + + int result = checkChannelMap(channelId); + + if (result >= 0) + { + result = handleNewConnectionFromProxy(channelType, channelId); + } + + if (result < 0) + { + // + // Realization of new channel failed. + // Send channel shutdown message to + // the peer proxy. + // + + if (handleControl(code_drop_connection, channelId) < 0) + { + return -1; + } + } + else + { + int fd = getFd(channelId); + + if (getReadable(fd) > 0) + { + #ifdef TEST + *logofs << "Proxy: Trying to read immediately " + << "from descriptor FD#" << fd << ".\n" + << logofs_flush; + #endif + + if (handleRead(fd) < 0) + { + return -1; + } + } + #ifdef TEST + *logofs << "Proxy: Nothing to read immediately " + << "from descriptor FD#" << fd << ".\n" + << logofs_flush; + #endif + } + + return 1; +} + +int Proxy::handleRead(int fd, const char *data, int size) +{ + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Handling data for connection on FD#" + << fd << ".\n" << logofs_flush; + #endif + + if (canRead(fd) == 0) + { + #if defined(TEST) || defined(INFO) + + if (getChannel(fd) < 0) + { + *logofs << "Proxy: PANIC! Can't read from invalid FD#" + << fd << ".\n" << logofs_flush; + + HandleCleanup(); + } + else + { + *logofs << "Proxy: WARNING! Read method called for FD#" + << fd << " but operation is not possible.\n" + << logofs_flush; + } + + #endif + + return 0; + } + + int channelId = getChannel(fd); + + // + // Let the channel object read all the new data from + // its file descriptor, isolate messages, compress + // those messages, and append the compressed form to + // the encode buffer. + // + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Reading messages from FD#" << fd + << " channel ID#" << channelId << ".\n" + << logofs_flush; + #endif + + int result = channels_[channelId] -> handleRead(encodeBuffer_, (const unsigned char *) data, + (unsigned int) size); + + // + // Even in the case of a failure, write the produced + // data to the proxy connection. To keep the stores + // synchronized, the remote side needs to decode any + // message encoded by this side, also if the X socket + // was closed in the meanwhile. If this is the case, + // the decompressed output will be silently discarded. + // + + if (result < 0) + { + #ifdef TEST + *logofs << "Proxy: Failed to read data from connection FD#" + << fd << " channel ID#" << channelId << ".\n" + << logofs_flush; + #endif + + if (handleFinish(channelId) < 0) + { + return -1; + } + } + + // + // Check if there are new splits or + // motion events to send. + // + + setSplitTimeout(channelId); + setMotionTimeout(channelId); + + return 1; +} + +int Proxy::handleEvents() +{ + #ifdef TEST + *logofs << "Proxy: Going to check the events on channels.\n" + << logofs_flush; + #endif + + // + // Check if we can safely write to the + // proxy link. + // + + int read = isTimeToRead(); + + // + // Loop on channels and send the pending + // events. We must copy the list because + // channels can be removed in the middle + // of the loop. + // + + T_list channelList = activeChannels_.copyList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] == NULL) + { + continue; + } + + // + // Check if we need to drop the channel. + // + + if (channels_[channelId] -> getDrop() == 1 || + channels_[channelId] -> getClosing() == 1) + { + #ifdef TEST + *logofs << "Proxy: Dropping the descriptor FD#" + << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + if (handleDrop(channelId) < 0) + { + return -1; + } + + continue; + } + else if (channels_[channelId] -> getFinish() == 1) + { + #ifdef TEST + *logofs << "Proxy: Skipping finishing " + << "descriptor FD#" << getFd(channelId) + << " channel ID#" << channelId << ".\n" + << logofs_flush; + #endif + + continue; + } + + // + // If the proxy link or the channel is + // in congestion state, don't handle + // the further events. + // + + if (read == 0 || congestions_[channelId] == 1) + { + #ifdef TEST + + if (read == 0) + { + *logofs << "Proxy: Can't handle events for FD#" + << getFd(channelId) << " channel ID#" + << channelId << " with proxy not available.\n" + << logofs_flush; + } + else + { + *logofs << "Proxy: Can't handle events for FD#" + << getFd(channelId) << " channel ID#" + << channelId << " with channel congested.\n" + << logofs_flush; + } + + #endif + + continue; + } + + // + // Handle the timeouts on the channel + // operations. + // + + int result = 0; + + // + // Handle the motion events. + // + + if (result >= 0 && channels_[channelId] -> needMotion() == 1) + { + if (isTimeToMotion() == 1) + { + #if defined(TEST) || defined(INFO) || defined(FLUSH) + + *logofs << "Proxy: FLUSH! Motion timeout expired after " + << diffTimestamp(timeouts_.motionTs, getTimestamp()) + << " Ms.\n" << logofs_flush; + + #endif + + result = channels_[channelId] -> handleMotion(encodeBuffer_); + + #ifdef TEST + + if (result < 0) + { + *logofs << "Proxy: Failed to handle motion events for FD#" + << getFd(channelId) << " channel ID#" << channelId + << ".\n" << logofs_flush; + } + + #endif + + timeouts_.motionTs = nullTimestamp(); + + setMotionTimeout(channelId); + } + #if defined(TEST) || defined(INFO) + else if (isTimestamp(timeouts_.motionTs) == 1) + { + *logofs << "Proxy: Running with " + << diffTimestamp(timeouts_.motionTs, getTimestamp()) + << " Ms elapsed since the last motion.\n" + << logofs_flush; + } + #endif + } + + if (result >= 0 && channels_[channelId] -> needSplit() == 1) + { + // + // Check if it is time to send more splits + // and how many bytes are going to be sent. + // + + if (isTimeToSplit() == 1) + { + #if defined(TEST) || defined(INFO) || defined(SPLIT) + *logofs << "Proxy: SPLIT! Split timeout expired after " + << diffTimestamp(timeouts_.splitTs, getTimestamp()) + << " Ms.\n" << logofs_flush; + #endif + + #if defined(TEST) || defined(INFO) || defined(SPLIT) + + *logofs << "Proxy: SPLIT! Encoding splits for FD#" + << getFd(channelId) << " at " << strMsTimestamp() + << " with " << clientStore_ -> getSplitTotalStorageSize() + << " total bytes and " << control -> SplitDataPacketLimit + << " bytes " << "to write.\n" + << logofs_flush; + + #endif + + result = channels_[channelId] -> handleSplit(encodeBuffer_); + + #ifdef TEST + + if (result < 0) + { + *logofs << "Proxy: Failed to handle splits for FD#" + << getFd(channelId) << " channel ID#" << channelId + << ".\n" << logofs_flush; + } + + #endif + + timeouts_.splitTs = nullTimestamp(); + + setSplitTimeout(channelId); + } + #if defined(TEST) || defined(INFO) || defined(SPLIT) + else if (channels_[channelId] -> needSplit() == 1 && + isTimestamp(timeouts_.splitTs) == 0) + { + *logofs << "Proxy: SPLIT! WARNING! Channel for FD#" + << getFd(channelId) << " has split to send but " + << "there is no timeout.\n" << logofs_flush; + } + else if (isTimestamp(timeouts_.splitTs) == 1) + { + *logofs << "Proxy: SPLIT! Running with " + << diffTimestamp(timeouts_.splitTs, getTimestamp()) + << " Ms elapsed since the last split.\n" + << logofs_flush; + } + #endif + } + + if (result < 0) + { + #ifdef TEST + *logofs << "Proxy: Error handling events for FD#" + << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + if (handleFinish(channelId) < 0) + { + return -1; + } + } + } + + return 1; +} + +int Proxy::handleFrame(T_frame_type type) +{ + // + // Write any outstanding control message, followed by the + // content of the encode buffer, to the proxy transport. + // + // This code assumes that the encode buffer data is at an + // offset several bytes from start of the buffer, so that + // the length header and any necessary control bytes can + // be inserted in front of the data already in the buffer. + // This is the easiest way to encapsulate header and data + // together in a single frame. + // + // The way framing is implemented is very efficient but + // inherently limited and does not allow for getting the + // best performance, especially when running over a fast + // link. Framing should be rewritten to include the length + // of the packets in a fixed size header and, possibly, + // to incapsulate the control messages and the channel's + // data in a pseudo X protocol message, so that the proxy + // itself would be treated like any other channel. + // + + #if defined(TEST) || defined(INFO) + + if (congestion_ == 1) + { + // + // This can happen because there may be control + // messages to send, like a proxy shutdown mes- + // sage or a statistics request. All the other + // cases should be considered an error. + // + + #ifdef WARNING + *logofs << "Proxy: WARNING! Data is to be sent while " + << "congestion is " << congestion_ << ".\n" + << logofs_flush; + #endif + } + + #endif + + // + // Check if there is any data available on + // the socket. Recent Linux kernels are very + // picky. They require that we read often or + // they assume that the process is non-inter- + // active. + // + + if (handleAsyncEvents() < 0) + { + return -1; + } + + // + // Check if this is a ping, not a data frame. + // + + if (type == frame_ping) + { + if (handleToken(frame_ping) < 0) + { + return -1; + } + } + + unsigned int dataLength = encodeBuffer_.getLength(); + + #ifdef DEBUG + *logofs << "Proxy: Data length is " << dataLength + << " control length is " << controlLength_ + << ".\n" << logofs_flush; + #endif + + if (dataLength > 0) + { + // + // If this is a generic channel we need + // to add the completion bits. Data can + // also have been encoded because of a + // statistics request, even if no output + // channel was currently selected. + // + + if (outputChannel_ != -1) + { + #if defined(TEST) || defined(INFO) + + if (channels_[outputChannel_] == NULL) + { + *logofs << "Proxy: PANIC! A new frame was requested " + << "but the channel is invalid.\n" + << logofs_flush; + + HandleCleanup(); + } + + #endif + + channels_[outputChannel_] -> handleCompletion(encodeBuffer_); + + dataLength = encodeBuffer_.getLength(); + } + } + else if (controlLength_ == 0) + { + #if defined(TEST) || defined(INFO) + + *logofs << "Proxy: PANIC! A new frame was requested " + << "but there is no data to write.\n" + << logofs_flush; + + HandleCleanup(); + + #endif + + return 0; + } + + #ifdef DEBUG + *logofs << "Proxy: Data length is now " << dataLength + << " control length is " << controlLength_ + << ".\n" << logofs_flush; + #endif + + // + // Check if this frame needs to carry a new + // token request. + // + + if (type == frame_data) + { + if (handleToken(frame_data) < 0) + { + return -1; + } + } + + #ifdef DEBUG + *logofs << "Proxy: Adding a new frame for the remote proxy.\n" + << logofs_flush; + #endif + + unsigned char temp[5]; + + unsigned int lengthLength = 0; + unsigned int shift = dataLength; + + while (shift) + { + temp[lengthLength++] = (unsigned char) (shift & 0x7f); + + shift >>= 7; + } + + unsigned char *data = encodeBuffer_.getData(); + + unsigned char *outputMessage = data - (controlLength_ + lengthLength); + + unsigned char *nextDest = outputMessage; + + for (int i = 0; i < controlLength_; i++) + { + *nextDest++ = controlCodes_[i]; + } + + for (int j = lengthLength - 1; j > 0; j--) + { + *nextDest++ = (temp[j] | 0x80); + } + + if (lengthLength) + { + *nextDest++ = temp[0]; + } + + unsigned int outputLength = dataLength + controlLength_ + lengthLength; + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Produced plain output for " << dataLength << "+" + << controlLength_ << "+" << lengthLength << " out of " + << outputLength << " bytes.\n" << logofs_flush; + #endif + + #if defined(TEST) || defined(INFO) || defined(FLUSH) || defined(TIME) + + T_timestamp nowTs = getTimestamp(); + + *logofs << "Proxy: FLUSH! Immediate with blocked " << transport_ -> + blocked() << " length " << transport_ -> length() + << " new " << outputLength << " flushable " << transport_ -> + flushable() << " tokens " << tokens_[token_control].remaining + << " after " << diffTimestamp(timeouts_.writeTs, nowTs) + << " Ms.\n" << logofs_flush; + + *logofs << "Proxy: FLUSH! Immediate flush to proxy FD#" << fd_ + << " of " << outputLength << " bytes at " << strMsTimestamp() + << " with priority " << priority_ << ".\n" << logofs_flush; + + *logofs << "Proxy: FLUSH! Current bitrate is " + << statistics -> getBitrateInShortFrame() << " with " + << statistics -> getBitrateInLongFrame() << " in the " + << "long frame and top " << statistics -> + getTopBitrate() << ".\n" << logofs_flush; + #endif + + statistics -> addWriteOut(); + + int result = transport_ -> write(write_immediate, outputMessage, outputLength); + + #ifdef TIME + + if (diffTimestamp(timeouts_.writeTs, nowTs) > 50) + { + *logofs << "Proxy: WARNING! TIME! Data written to proxy FD#" + << fd_ << " at " << strMsTimestamp() << " after " + << diffTimestamp(timeouts_.writeTs, nowTs) + << " Ms.\n" << logofs_flush; + } + + #endif + + #ifdef DUMP + *logofs << "Proxy: Sent " << outputLength << " bytes of data " + << "with checksum "; + + DumpChecksum(outputMessage, outputLength); + + *logofs << " on proxy FD#" << fd_ << ".\n" << logofs_flush; + #endif + + #ifdef DUMP + *logofs << "Proxy: Partial checksums are:\n"; + + DumpBlockChecksums(outputMessage, outputLength, 256); + + *logofs << logofs_flush; + #endif + + // + // Clean up the encode buffer and + // bring it to the initial size. + // + + encodeBuffer_.fullReset(); + + // + // Close the connection if we got + // an error. + // + + if (result < 0) + { + #ifdef TEST + *logofs << "Proxy: Failed write to proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + return -1; + } + + // + // Account for the data frame and the + // framing overhead. + // + + if (dataLength > 0) + { + statistics -> addFrameOut(); + } + + statistics -> addFramingBits((controlLength_ + lengthLength) << 3); + + controlLength_ = 0; + + // + // Reset all buffers, counters and the + // priority flag. + // + + handleResetFlush(); + + // + // Check if more data became available + // after writing. + // + + if (handleAsyncEvents() < 0) + { + return -1; + } + + // + // Drain the proxy link if we are in + // congestion state. + // + // if (needDrain() == 1 && draining_ == 0) + // { + // if (handleDrain() < 0) + // { + // return -1; + // } + // } + // + + return result; +} + +int Proxy::handleFlush() +{ + // + // We can have data in the encode buffer or + // control bytes to send. In the case make + // up a new frame. + // + + if (encodeBuffer_.getLength() + controlLength_ > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Flushing data in the encode buffer.\n" + << logofs_flush; + #endif + + priority_ = 1; + + if (handleFrame(frame_data) < 0) + { + return -1; + } + } + + // + // Check if we have something to write. + // + + if (transport_ -> length() + transport_ -> flushable() == 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Nothing else to flush for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + return 0; + } + + #if defined(TEST) || defined(INFO) + + if (transport_ -> blocked() == 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Proxy descriptor FD#" << fd_ + << " has data to flush but the transport " + << "is not blocked.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Proxy descriptor FD#" << fd_ + << " has data to flush but the transport " + << "is not blocked.\n"; + + HandleCleanup(); + } + + #endif + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "Proxy: FLUSH! Deferred with blocked " << transport_ -> + blocked() << " length " << transport_ -> length() + << " flushable " << transport_ -> flushable() << " tokens " + << tokens_[token_control].remaining << ".\n" + << logofs_flush; + + *logofs << "Proxy: FLUSH! Deferred flush to proxy FD#" << fd_ + << " of " << transport_ -> length() + transport_ -> + flushable() << " bytes at " << strMsTimestamp() + << " with priority " << priority_ << ".\n" + << logofs_flush; + + *logofs << "Proxy: FLUSH! Current bitrate is " + << statistics -> getBitrateInShortFrame() << " with " + << statistics -> getBitrateInLongFrame() << " in the " + << "long frame and top " << statistics -> + getTopBitrate() << ".\n" << logofs_flush; + #endif + + statistics -> addWriteOut(); + + int result = transport_ -> flush(); + + if (result < 0) + { + return -1; + } + + // + // Reset the counters and update the + // timestamp of the last write. + // + + handleResetFlush(); + + return result; +} + +int Proxy::handleDrain() +{ + // + // If the proxy is run in the same process + // as SSH, we can't block or the program + // would not have a chance to read or write + // its data. + // + + if (control -> LinkEncrypted == 1) + { + return 0; + } + + if (needDrain() == 0 || draining_ == 1) + { + #if defined(TEST) || defined(INFO) + + if (draining_ == 1) + { + *logofs << "Proxy: WARNING! Already draining proxy FD#" + << fd_ << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + } + else + { + *logofs << "Proxy: WARNING! No need to drain proxy FD#" + << fd_ << " with congestion " << congestion_ + << " length " << transport_ -> length() + << " and blocked " << transport_ -> blocked() + << ".\n" << logofs_flush; + } + + #endif + + return 0; + } + + draining_ = 1; + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Going to drain the proxy FD#" << fd_ + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + int timeout = control -> PingTimeout / 2; + + T_timestamp startTs = getNewTimestamp(); + + T_timestamp nowTs = startTs; + + int remaining; + int result; + + // + // Keep draining the proxy socket while + // reading the incoming messages until + // the timeout is expired. + // + + for (;;) + { + remaining = timeout - diffTimestamp(startTs, nowTs); + + if (remaining <= 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Timeout raised while draining " + << "FD#" << fd_ << " at " << strMsTimestamp() + << " after " << diffTimestamp(startTs, nowTs) + << " Ms.\n" << logofs_flush; + #endif + + result = 0; + + goto ProxyDrainEnd; + } + + if (transport_ -> length() > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Trying to write to FD#" << fd_ + << " at " << strMsTimestamp() << " with length " + << transport_ -> length() << " and " + << remaining << " Ms remaining.\n" + << logofs_flush; + #endif + + result = transport_ -> drain(0, remaining); + + if (result == -1) + { + result = -1; + + goto ProxyDrainEnd; + } + else if (result == 0 && transport_ -> readable() > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Decoding more data from proxy FD#" + << fd_ << " at " << strMsTimestamp() << " with " + << transport_ -> length() << " bytes to write and " + << transport_ -> readable() << " readable.\n" + << logofs_flush; + #endif + + if (handleRead() < 0) + { + result = -1; + + goto ProxyDrainEnd; + } + } + #if defined(TEST) || defined(INFO) + else if (result == 1) + { + *logofs << "Proxy: Transport for proxy FD#" << fd_ + << " drained down to " << transport_ -> length() + << " bytes.\n" << logofs_flush; + } + #endif + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Waiting for more data from proxy " + << "FD#" << fd_ << " at " << strMsTimestamp() + << " with " << remaining << " Ms remaining.\n" + << logofs_flush; + #endif + + + result = transport_ -> wait(remaining); + + if (result == -1) + { + result = -1; + + goto ProxyDrainEnd; + } + else if (result > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Decoding more data from proxy FD#" + << fd_ << " at " << strMsTimestamp() << " with " + << transport_ -> readable() << " bytes readable.\n" + << logofs_flush; + #endif + + if (handleRead() < 0) + { + result = -1; + + goto ProxyDrainEnd; + } + } + } + + // + // Check if we finally got the tokens + // that would allow us to come out of + // the congestion state. + // + + if (needDrain() == 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Got decongestion for proxy FD#" + << fd_ << " at " << strMsTimestamp() << " after " + << diffTimestamp(startTs, getTimestamp()) + << " Ms.\n" << logofs_flush; + #endif + + result = 1; + + goto ProxyDrainEnd; + } + + nowTs = getNewTimestamp(); + } + +ProxyDrainEnd: + + draining_ = 0; + + return result; +} + +int Proxy::handleFlush(int fd) +{ + int channelId = getChannel(fd); + + if (channelId < 0 || channels_[channelId] == NULL) + { + #ifdef TEST + *logofs << "Proxy: WARNING! Skipping flush on invalid " + << "descriptor FD#" << fd << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + return 0; + } + else if (channels_[channelId] -> getFinish() == 1) + { + #ifdef TEST + *logofs << "Proxy: Skipping flush on finishing " + << "descriptor FD#" << fd << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + return 0; + } + + #ifdef TEST + *logofs << "Proxy: Going to flush FD#" << fd + << " with blocked " << transports_[channelId] -> blocked() + << " length " << transports_[channelId] -> length() + << ".\n" << logofs_flush; + #endif + + if (channels_[channelId] -> handleFlush() < 0) + { + #ifdef TEST + *logofs << "Proxy: Failed to flush data to FD#" + << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + handleFinish(channelId); + + return -1; + } + + return 1; +} + +int Proxy::handleStatistics(int type, ostream *stream) +{ + if (stream == NULL || control -> EnableStatistics == 0) + { + #ifdef WARNING + *logofs << "Proxy: WARNING! Cannot produce statistics " + << " for proxy FD#" << fd_ << ". Invalid settings " + << "for statistics or stream.\n" << logofs_flush; + #endif + + return 0; + } + else if (currentStatistics_ != NULL) + { + // + // Need to update the stream pointer as the + // previous one could have been destroyed. + // + + #ifdef WARNING + *logofs << "Proxy: WARNING! Replacing stream while producing " + << "statistics in stream at " << currentStatistics_ + << " for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + } + + currentStatistics_ = stream; + + // + // Get statistics of remote peer. + // + + if (handleControl(code_statistics_request, type) < 0) + { + return -1; + } + + return 1; +} + +int Proxy::handleStatisticsFromProxy(int type) +{ + if (needFlush() == 1) + { + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "Proxy: WARNING! Data for the previous " + << "channel ID#" << outputChannel_ + << " flushed in statistics.\n" + << logofs_flush; + #endif + + if (handleFrame(frame_data) < 0) + { + return -1; + } + } + + if (control -> EnableStatistics == 1) + { + // + // Allocate a buffer for the output. + // + + char *buffer = new char[STATISTICS_LENGTH]; + + *buffer = '\0'; + + if (control -> ProxyMode == proxy_client) + { + #ifdef TEST + *logofs << "Proxy: Producing " + << (type == TOTAL_STATS ? "total" : "partial") + << " client statistics for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + statistics -> getClientProtocolStats(type, buffer); + + statistics -> getClientOverallStats(type, buffer); + } + else + { + #ifdef TEST + *logofs << "Proxy: Producing " + << (type == TOTAL_STATS ? "total" : "partial") + << " server statistics for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + statistics -> getServerProtocolStats(type, buffer); + } + + if (type == PARTIAL_STATS) + { + statistics -> resetPartialStats(); + } + + unsigned int length = strlen((char *) buffer) + 1; + + encodeBuffer_.encodeValue(type, 8); + + encodeBuffer_.encodeValue(length, 32); + + #ifdef TEST + *logofs << "Proxy: Encoding " << length + << " bytes of statistics data for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + encodeBuffer_.encodeMemory((unsigned char *) buffer, length); + + // + // Account statistics data as framing bits. + // + + statistics -> addFramingBits(length << 3); + + delete [] buffer; + } + else + { + #ifdef WARNING + *logofs << "Proxy: WARNING! Got statistics request " + << "but local statistics are disabled.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Got statistics request " + << "but local statistics are disabled.\n"; + + type = NO_STATS; + + encodeBuffer_.encodeValue(type, 8); + + #ifdef TEST + *logofs << "Proxy: Sending error code to remote proxy on FD#" + << fd_ << ".\n" << logofs_flush; + #endif + } + + // + // The next write will flush the statistics + // data and the control message. + // + + if (handleControl(code_statistics_reply, type) < 0) + { + return -1; + } + + return 1; +} + +int Proxy::handleStatisticsFromProxy(const unsigned char *message, unsigned int length) +{ + if (currentStatistics_ == NULL) + { + #ifdef WARNING + *logofs << "Proxy: WARNING! Unexpected statistics data received " + << "from remote proxy on FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Unexpected statistics data received " + << "from remote proxy.\n"; + + return 0; + } + + // + // Allocate the decode buffer and at least + // the 'type' field to see if there was an + // error. + // + + DecodeBuffer decodeBuffer(message, length); + + unsigned int type; + + decodeBuffer.decodeValue(type, 8); + + if (type == NO_STATS) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Couldn't get statistics from remote " + << "proxy on FD#" << fd_ << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Couldn't get statistics from remote proxy.\n"; + } + else if (type != TOTAL_STATS && type != PARTIAL_STATS) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Cannot produce statistics " + << "with qualifier '" << type << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Cannot produce statistics " + << "with qualifier '" << type << "'.\n"; + + return -1; + } + else + { + unsigned int size; + + decodeBuffer.decodeValue(size, 32); + + char *buffer = new char[STATISTICS_LENGTH]; + + *buffer = '\0'; + + if (control -> EnableStatistics == 1) + { + if (control -> ProxyMode == proxy_client) + { + #ifdef TEST + *logofs << "Proxy: Finalizing " + << (type == TOTAL_STATS ? "total" : "partial") + << " client statistics for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + statistics -> getClientCacheStats(type, buffer); + + #ifdef TEST + *logofs << "Proxy: Decoding " << size + << " bytes of statistics data for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + strncat(buffer, (char *) decodeBuffer.decodeMemory(size), size); + + statistics -> getClientProtocolStats(type, buffer); + + statistics -> getClientOverallStats(type, buffer); + } + else + { + #ifdef TEST + *logofs << "Proxy: Finalizing " + << (type == TOTAL_STATS ? "total" : "partial") + << " server statistics for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + statistics -> getServerCacheStats(type, buffer); + + statistics -> getServerProtocolStats(type, buffer); + + #ifdef TEST + *logofs << "Proxy: Decoding " << size + << " bytes of statistics data for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + strncat(buffer, (char *) decodeBuffer.decodeMemory(size), size); + } + + if (type == PARTIAL_STATS) + { + statistics -> resetPartialStats(); + } + + *currentStatistics_ << buffer; + + // + // Mark the end of text to help external parsing. + // + + *currentStatistics_ << '\4'; + + *currentStatistics_ << flush; + } + else + { + // + // It can be that statistics were enabled at the time + // we issued the request (otherwise we could not have + // set the stream), but now they have been disabled + // by user. We must decode statistics data if we want + // to keep the connection. + // + + #ifdef TEST + *logofs << "Proxy: Discarding " << size + << " bytes of statistics data for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + strncat(buffer, (char *) decodeBuffer.decodeMemory(size), size); + } + + delete [] buffer; + } + + currentStatistics_ = NULL; + + return 1; +} + +int Proxy::handleNegotiation(const unsigned char *message, unsigned int length) +{ + #ifdef PANIC + *logofs << "Proxy: PANIC! Writing data during proxy " + << "negotiation is not implemented.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Writing data during proxy " + << "negotiation is not implemented.\n"; + + return -1; +} + +int Proxy::handleNegotiationFromProxy(const unsigned char *message, unsigned int length) +{ + #ifdef PANIC + *logofs << "Proxy: PANIC! Reading data during proxy " + << "negotiation is not implemented.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Reading data during proxy " + << "negotiation is not implemented.\n"; + + return -1; +} + +int Proxy::handleAlert(int alert) +{ + if (handleControl(code_alert_request, alert) < 0) + { + return -1; + } + + return 1; +} + +int Proxy::handleCloseConnection(int clientFd) +{ + int channelId = getChannel(clientFd); + + if (channels_[channelId] != NULL && + channels_[channelId] -> getFinish() == 0) + { + #ifdef TEST + *logofs << "Proxy: Closing down the channel for FD#" + << clientFd << ".\n" << logofs_flush; + #endif + + if (handleFinish(channelId) < 0) + { + return -1; + } + + return 1; + } + + return 0; +} + +int Proxy::handleCloseAllXConnections() +{ + #ifdef TEST + *logofs << "Proxy: Closing down any remaining X channel.\n" + << logofs_flush; + #endif + + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] != NULL && + channels_[channelId] -> getType() == channel_x11 && + channels_[channelId] -> getFinish() == 0) + { + #ifdef TEST + *logofs << "Proxy: Closing down the channel for FD#" + << getFd(channelId) << ".\n" << logofs_flush; + #endif + + if (handleFinish(channelId) < 0) + { + return -1; + } + } + } + + return 1; +} + +int Proxy::handleCloseAllListeners() +{ + // Since ProtoStep7 (#issue 108) + if (finish_ == 0) + { + #ifdef TEST + *logofs << "Proxy: Closing down all remote listeners.\n" + << logofs_flush; + #endif + + if (handleControl(code_finish_listeners) < 0) + { + return -1; + } + + finish_ = 1; + } + + return 1; +} + +void Proxy::handleResetAlert() +{ + if (alert_ != 0) + { + #ifdef TEST + *logofs << "Proxy: The proxy alert '" << alert_ + << "' was displaced.\n" << logofs_flush; + #endif + + alert_ = 0; + } + + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] != NULL) + { + channels_[channelId] -> handleResetAlert(); + } + } +} + +int Proxy::handleFinish(int channelId) +{ + // + // Send any outstanding encoded data and + // do any finalization needed on the + // channel. + // + + if (needFlush(channelId) == 1) + { + if (channels_[channelId] -> getFinish() == 1) + { + #ifdef WARNING + *logofs << "Proxy: WARNING! The finishing channel ID#" + << channelId << " has data to flush.\n" + << logofs_flush; + #endif + } + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "Proxy: WARNING! Flushing data for the " + << "finishing channel ID#" << channelId + << ".\n" << logofs_flush; + #endif + + if (handleFrame(frame_data) < 0) + { + return -1; + } + } + + // + // Reset the congestion state and the + // timeouts, if needed. + // + + congestions_[channelId] = 0; + + setSplitTimeout(channelId); + setMotionTimeout(channelId); + + if (channels_[channelId] -> getFinish() == 0) + { + channels_[channelId] -> handleFinish(); + + // + // Force a failure in the case somebody + // would try to read from the channel. + // + + shutdown(getFd(channelId), SHUT_RD); + + // + // If the failure was not originated by + // the remote, send a channel shutdown + // message. + // + + if (channels_[channelId] -> getClosing() == 0) + { + #ifdef TEST + *logofs << "Proxy: Finishing channel for FD#" + << getFd(channelId) << " channel ID#" + << channelId << " because of failure.\n" + << logofs_flush; + #endif + + if (handleControl(code_finish_connection, channelId) < 0) + { + return -1; + } + } + } + + return 1; +} + +int Proxy::handleFinishFromProxy(int channelId) +{ + // + // Check if this channel has pending + // data to send. + // + + if (needFlush(channelId) == 1) + { + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "Proxy: WARNING! Flushing data for the " + << "finishing channel ID#" << channelId + << ".\n" << logofs_flush; + #endif + + if (handleFrame(frame_data) < 0) + { + return -1; + } + } + + // + // Mark the channel. We will free its + // resources at the next loop and will + // send the drop message to the remote. + // + + if (channels_[channelId] -> getClosing() == 0) + { + #ifdef TEST + *logofs << "Proxy: Marking channel for FD#" + << getFd(channelId) << " channel ID#" + << channelId << " as closing.\n" + << logofs_flush; + #endif + + channels_[channelId] -> handleClosing(); + } + + if (channels_[channelId] -> getFinish() == 0) + { + #ifdef TEST + *logofs << "Proxy: Finishing channel for FD#" + << getFd(channelId) << " channel ID#" + << channelId << " because of proxy.\n" + << logofs_flush; + #endif + + channels_[channelId] -> handleFinish(); + } + + if (handleFinish(channelId) < 0) + { + return -1; + } + + return 1; +} + +int Proxy::handleDropFromProxy(int channelId) +{ + // + // Only mark the channel. + // + + #ifdef TEST + *logofs << "Proxy: Marking channel for FD#" + << getFd(channelId) << " channel ID#" + << channelId << " as being dropped.\n" + << logofs_flush; + #endif + + if (channels_[channelId] -> getDrop() == 0) + { + channels_[channelId] -> handleDrop(); + } + + return 1; +} + +// +// Close the channel and deallocate all its +// resources. +// + +int Proxy::handleDrop(int channelId) +{ + // + // Check if this channel has pending + // data to send. + // + + if (needFlush(channelId) == 1) + { + if (channels_[channelId] -> getFinish() == 1) + { + #ifdef WARNING + *logofs << "Proxy: WARNING! The dropping channel ID#" + << channelId << " has data to flush.\n" + << logofs_flush; + #endif + } + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "Proxy: WARNING! Flushing data for the " + << "dropping channel ID#" << channelId + << ".\n" << logofs_flush; + #endif + + if (handleFrame(frame_data) < 0) + { + return -1; + } + } + + #ifdef TEST + *logofs << "Proxy: Dropping channel for FD#" + << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + if (channels_[channelId] -> getFinish() == 0) + { + #ifdef WARNING + *logofs << "Proxy: WARNING! The channel for FD#" + << getFd(channelId) << " channel ID#" + << channelId << " was not marked as " + << "finishing.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": The channel for FD#" + << getFd(channelId) << " channel ID#" + << channelId << " was not marked as " + << "finishing.\n"; + + channels_[channelId] -> handleFinish(); + } + + // + // Send the channel shutdown message + // to the peer proxy. + // + + if (channels_[channelId] -> getClosing() == 1) + { + if (handleControl(code_drop_connection, channelId) < 0) + { + return -1; + } + } + + // + // Get rid of the channel. + // + + if (channels_[channelId] -> getType() != channel_x11) + { + #ifdef TEST + *logofs << "Proxy: Closed connection to " + << getTypeName(channels_[channelId] -> getType()) + << " server.\n" << logofs_flush; + #endif + + cerr << "Info" << ": Closed connection to " + << getTypeName(channels_[channelId] -> getType()) + << " server.\n"; + } + + delete channels_[channelId]; + channels_[channelId] = NULL; + + cleanupChannelMap(channelId); + + // + // Get rid of the transport. + // + + deallocateTransport(channelId); + + congestions_[channelId] = 0; + + decreaseChannels(channelId); + + // + // Check if the channel was the + // one currently selected for + // output. + // + + if (outputChannel_ == channelId) + { + outputChannel_ = -1; + } + + return 1; +} + +// +// Send an empty message to the remote peer +// to verify if the link is alive and let +// the remote proxy detect a congestion. +// + +int Proxy::handlePing() +{ + T_timestamp nowTs = getTimestamp(); + + #if defined(DEBUG) || defined(PING) + + *logofs << "Proxy: Checking ping at " + << strMsTimestamp(nowTs) << logofs_flush; + + *logofs << " with last loop at " + << strMsTimestamp(timeouts_.loopTs) << ".\n" + << logofs_flush; + + *logofs << "Proxy: Last bytes in at " + << strMsTimestamp(timeouts_.readTs) << logofs_flush; + + *logofs << " last bytes out at " + << strMsTimestamp(timeouts_.writeTs) << ".\n" + << logofs_flush; + + *logofs << "Proxy: Last ping at " + << strMsTimestamp(timeouts_.pingTs) << ".\n" + << logofs_flush; + + #endif + + // + // Be sure we take into account any clock drift. This + // can be caused by the user changing the system timer + // or by small adjustments introduced by the operating + // system making the clock go backward. + // + + if (checkDiffTimestamp(timeouts_.loopTs, nowTs) == 0) + { + #ifdef WARNING + *logofs << "Proxy: WARNING! Detected drift in system " + << "timer. Resetting to current time.\n" + << logofs_flush; + #endif + + timeouts_.pingTs = nowTs; + timeouts_.readTs = nowTs; + timeouts_.writeTs = nowTs; + } + + // + // Check timestamp of last read from remote proxy. It can + // happen that we stayed in the main loop long enough to + // have idle timeout expired, for example if the proxy was + // stopped and restarted or because of an extremely high + // load of the system. In this case we don't complain if + // there is something new to read from the remote. + // + + int diffIn = diffTimestamp(timeouts_.readTs, nowTs); + + if (diffIn >= (control -> PingTimeout * 2) - + control -> LatencyTimeout) + { + // + // Force a read to detect whether the remote proxy + // aborted the connection. + // + + int result = handleRead(); + + if (result < 0) + { + #if defined(TEST) || defined(INFO) || defined(PING) + *logofs << "Proxy: WARNING! Detected shutdown waiting " + << "for the ping after " << diffIn / 1000 + << " seconds.\n" << logofs_flush; + #endif + + return -1; + } + else if (result > 0) + { + diffIn = diffTimestamp(timeouts_.readTs, nowTs); + + if (handleFlush() < 0) + { + return -1; + } + } + } + + if (diffIn >= (control -> PingTimeout * 2) - + control -> LatencyTimeout) + { + #if defined(TEST) || defined(INFO) || defined(PING) + *logofs << "Proxy: Detected congestion at " + << strMsTimestamp() << " with " << diffIn / 1000 + << " seconds since the last read.\n" + << logofs_flush; + #endif + + // + // There are two types of proxy congestion. The first, + // affecting the ability of the proxy to write the + // encoded data to the network, is controlled by the + // congestion_ flag. The flag is raised when no data + // is received from the remote proxy within a timeout. + // On the X client side, the flag is also raised when + // the proxy runs out of tokens. + // + + if (control -> ProxyMode == proxy_server) + { + // + // At X server side we must return to read data + // from the channels after a while, because we + // need to give a chance to the channel to read + // the key sequence CTRL+ALT+SHIFT+ESC. + // + + if (congestion_ == 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Forcibly entering congestion due to " + << "timeout with " << tokens_[token_control].remaining + << " tokens.\n" << logofs_flush; + #endif + + congestion_ = 1; + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Forcibly exiting congestion due to " + << "timeout with " << tokens_[token_control].remaining + << " tokens.\n" << logofs_flush; + #endif + + congestion_ = 0; + } + } + else + { + #if defined(TEST) || defined(INFO) + + if (congestion_ == 0) + { + *logofs << "Proxy: Entering congestion due to timeout " + << "with " << tokens_[token_control].remaining + << " tokens.\n" << logofs_flush; + } + + #endif + + congestion_ = 1; + } + + if (control -> ProxyTimeout > 0 && + diffIn >= (control -> ProxyTimeout - + control -> LatencyTimeout)) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! No data received from " + << "remote proxy on FD#" << fd_ << " within " + << (diffIn + control -> LatencyTimeout) / 1000 + << " seconds.\n" << logofs_flush; + #endif + + cerr << "Error" << ": No data received from remote " + << "proxy within " << (diffIn + control -> + LatencyTimeout) / 1000 << " seconds.\n"; + + HandleAbort(); + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: WARNING! No data received from " + << "remote proxy on FD#" << fd_ << " since " + << diffIn << " Ms.\n" << logofs_flush; + #endif + + if (control -> ProxyTimeout > 0 && + isTimestamp(timeouts_.alertTs) == 0 && + diffIn >= (control -> ProxyTimeout - + control -> LatencyTimeout) / 4) + { + // + // If we are in the middle of a shutdown + // procedure but the remote is not resp- + // onding, force the closure of the link. + // + + if (finish_ != 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! No response received from " + << "the remote proxy on FD#" << fd_ << " while " + << "waiting for the shutdown.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": No response received from remote " + << "proxy while waiting for the shutdown.\n"; + + HandleAbort(); + } + else + { + cerr << "Warning" << ": No data received from remote " + << "proxy within " << (diffIn + control -> + LatencyTimeout) / 1000 << " seconds.\n"; + + if (alert_ == 0) + { + if (control -> ProxyMode == proxy_client) + { + alert_ = CLOSE_DEAD_PROXY_CONNECTION_CLIENT_ALERT; + } + else + { + alert_ = CLOSE_DEAD_PROXY_CONNECTION_SERVER_ALERT; + } + + HandleAlert(alert_, 1); + } + + timeouts_.alertTs = nowTs; + } + } + } + } + + // + // Check if we need to update the congestion + // counter. + // + + int diffOut = diffTimestamp(timeouts_.writeTs, nowTs); + + if (agent_ != nothing && congestions_[agent_] == 0 && + statistics -> getCongestionInFrame() >= 1 && + diffOut >= (control -> IdleTimeout - + control -> LatencyTimeout * 5)) + { + #if defined(TEST) || defined(INFO) || defined(PING) + *logofs << "Proxy: Forcing an update of the " + << "congestion counter after timeout.\n" + << logofs_flush; + #endif + + statistics -> updateCongestion(tokens_[token_control].remaining, + tokens_[token_control].limit); + } + + // + // Send a new token if we didn't send any data to + // the remote for longer than the ping timeout. + // The client side sends a token, the server side + // responds with a token reply. + // + // VMWare virtual machines can have the system + // timer deadly broken. Try to send a ping regard- + // less we are the client or the server proxy to + // force a write by the remote. + // + + if (control -> ProxyMode == proxy_client || + diffIn >= (control -> PingTimeout * 4) - + control -> LatencyTimeout) + { + // + // We need to send a new ping even if we didn't + // receive anything from the remote within the + // ping timeout. The server side will respond + // to our ping, so we use the ping to force the + // remote end to send some data. + // + + if (diffIn >= (control -> PingTimeout - + control -> LatencyTimeout * 5) || + diffOut >= (control -> PingTimeout - + control -> LatencyTimeout * 5)) + { + int diffPing = diffTimestamp(timeouts_.pingTs, nowTs); + + if (diffPing < 0 || diffPing >= (control -> PingTimeout - + control -> LatencyTimeout * 5)) + { + #if defined(TEST) || defined(INFO) || defined(PING) + *logofs << "Proxy: Sending a new ping at " << strMsTimestamp() + << " with " << tokens_[token_control].remaining + << " tokens and elapsed in " << diffIn << " out " + << diffOut << " ping " << diffPing + << ".\n" << logofs_flush; + #endif + + if (handleFrame(frame_ping) < 0) + { + return -1; + } + + timeouts_.pingTs = nowTs; + } + #if defined(TEST) || defined(INFO) || defined(PING) + else + { + *logofs << "Proxy: Not sending a new ping with " + << "elapsed in " << diffIn << " out " + << diffOut << " ping " << diffPing + << ".\n" << logofs_flush; + } + #endif + } + } + + return 1; +} + +int Proxy::handleSyncFromProxy(int channelId) +{ + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: WARNING! Received a synchronization " + << "request from the remote proxy.\n" + << logofs_flush; + #endif + + if (handleControl(code_sync_reply, channelId) < 0) + { + return -1; + } + + return 1; +} + +int Proxy::handleResetStores() +{ + // + // Recreate the message stores. + // + + delete clientStore_; + delete serverStore_; + + clientStore_ = new ClientStore(compressor_); + serverStore_ = new ServerStore(compressor_); + + timeouts_.loadTs = nullTimestamp(); + + // + // Replace message stores in channels. + // + + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] != NULL) + { + if (channels_[channelId] -> setStores(clientStore_, serverStore_) < 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Failed to replace message stores in " + << "channel for FD#" << getFd(channelId) << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed to replace message stores in " + << "channel for FD#" << getFd(channelId) << ".\n"; + + return -1; + } + #ifdef TEST + else + { + *logofs << "Proxy: Replaced message stores in channel " + << "for FD#" << getFd(channelId) << ".\n" + << logofs_flush; + } + #endif + } + } + + return 1; +} + +int Proxy::handleResetPersistentCache() +{ + char *fullName = new char[strlen(control -> PersistentCachePath) + + strlen(control -> PersistentCacheName) + 2]; + + strcpy(fullName, control -> PersistentCachePath); + strcat(fullName, "/"); + strcat(fullName, control -> PersistentCacheName); + + #ifdef TEST + *logofs << "Proxy: Going to remove persistent cache file '" + << fullName << "'\n" << logofs_flush; + #endif + + unlink(fullName); + + delete [] fullName; + + delete [] control -> PersistentCacheName; + + control -> PersistentCacheName = NULL; + + return 1; +} + +void Proxy::handleResetFlush() +{ + #ifdef TEST + *logofs << "Proxy: Going to reset flush counters " + << "for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + // + // Reset the proxy priority flag. + // + + priority_ = 0; + + // + // Restore buffers to their initial + // size. + // + + transport_ -> partialReset(); + + // + // Update the timestamp of the last + // write operation performed on the + // socket. + // + + timeouts_.writeTs = getTimestamp(); +} + +int Proxy::handleFinish() +{ + // + // Reset the timestamps to give the proxy + // another chance to show the 'no response' + // dialog if the shutdown message doesn't + // come in time. + // + + timeouts_.readTs = getTimestamp(); + + timeouts_.alertTs = nullTimestamp(); + + finish_ = 1; + + return 1; +} + +int Proxy::handleShutdown() +{ + // + // Send shutdown message to remote proxy. + // + + shutdown_ = 1; + + handleControl(code_shutdown_request); + + #ifdef TEST + *logofs << "Proxy: Starting shutdown procedure " + << "for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + // + // Ensure that all the data accumulated + // in the transport buffer is flushed + // to the network layer. + // + + for (int i = 0; i < 100; i++) + { + if (canFlush() == 1) + { + handleFlush(); + } + else + { + break; + } + + usleep(100000); + } + + // + // Now wait for the network layers to + // consume all the data. + // + + for (int i = 0; i < 100; i++) + { + if (transport_ -> queued() <= 0) + { + break; + } + + usleep(100000); + } + + // + // Give time to the remote end to read + // the shutdown message and close the + // connection. + // + + transport_ -> wait(10000); + + #ifdef TEST + *logofs << "Proxy: Ending shutdown procedure " + << "for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + return 1; +} + +int Proxy::handleChannelConfiguration() +{ + if (activeChannels_.getSize() == 0) + { + #ifdef TEST + *logofs << "Proxy: Going to initialize the static " + << "members in channels for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + Channel::setReferences(); + + ClientChannel::setReferences(); + ServerChannel::setReferences(); + + GenericChannel::setReferences(); + } + + return 1; +} + +int Proxy::handleSocketConfiguration() +{ + // + // Set linger mode on proxy to correctly + // get shutdown notification. + // + + SetLingerTimeout(fd_, 30); + + // + // Set keep-alive on socket so that if remote link + // terminates abnormally (as killed hard or because + // of a power-off) process will get a SIGPIPE. In + // practice this is useless as proxies already ping + // each other every few seconds. + // + + if (control -> OptionProxyKeepAlive == 1) + { + SetKeepAlive(fd_); + } + + // + // Set 'priority' flag at TCP layer for path + // proxy-to-proxy. Look at IPTOS_LOWDELAY in + // man 7 ip. + // + + if (control -> OptionProxyLowDelay == 1) + { + SetLowDelay(fd_); + } + + // + // Update size of TCP send and receive buffers. + // + + if (control -> OptionProxySendBuffer != -1) + { + SetSendBuffer(fd_, control -> OptionProxySendBuffer); + } + + if (control -> OptionProxyReceiveBuffer != -1) + { + SetReceiveBuffer(fd_, control -> OptionProxyReceiveBuffer); + } + + // + // Update TCP_NODELAY settings. Note that on old Linux + // kernels turning off the Nagle algorithm didn't work + // when proxy was run through a PPP link. Trying to do + // so caused the kernel to stop delivering data to us + // if a serious network congestion was encountered. + // + + if (control -> ProxyMode == proxy_client) + { + if (control -> OptionProxyClientNoDelay != -1) + { + SetNoDelay(fd_, control -> OptionProxyClientNoDelay); + } + } + else + { + if (control -> OptionProxyServerNoDelay != -1) + { + SetNoDelay(fd_, control -> OptionProxyServerNoDelay); + } + } + + return 1; +} + +int Proxy::handleLinkConfiguration() +{ + #ifdef TEST + *logofs << "Proxy: Propagating parameters to " + << "channels' read buffers.\n" + << logofs_flush; + #endif + + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] != NULL) + { + channels_[channelId] -> handleConfiguration(); + } + } + + #ifdef TEST + *logofs << "Proxy: Propagating parameters to " + << "proxy buffers.\n" + << logofs_flush; + #endif + + readBuffer_.setSize(control -> ProxyInitialReadSize, + control -> ProxyMaximumBufferSize); + + encodeBuffer_.setSize(control -> TransportProxyBufferSize, + control -> TransportProxyBufferThreshold, + control -> TransportMaximumBufferSize); + + transport_ -> setSize(control -> TransportProxyBufferSize, + control -> TransportProxyBufferThreshold, + control -> TransportMaximumBufferSize); + + #ifdef TEST + *logofs << "Proxy: Configuring the proxy timeouts.\n" + << logofs_flush; + #endif + + timeouts_.split = control -> SplitTimeout; + timeouts_.motion = control -> MotionTimeout; + + #ifdef TEST + *logofs << "Proxy: Configuring the proxy tokens.\n" + << logofs_flush; + #endif + + tokens_[token_control].size = control -> TokenSize; + tokens_[token_control].limit = control -> TokenLimit; + + if (tokens_[token_control].limit < 1) + { + tokens_[token_control].limit = 1; + } + + #if defined(TEST) || defined(INFO) || defined(LIMIT) + *logofs << "Proxy: TOKEN! LIMIT! Setting token [" + << DumpToken(token_control) << "] size to " + << tokens_[token_control].size << " and limit to " + << tokens_[token_control].limit << ".\n" + << logofs_flush; + #endif + + tokens_[token_split].size = control -> TokenSize; + tokens_[token_split].limit = control -> TokenLimit / 2; + + if (tokens_[token_split].limit < 1) + { + tokens_[token_split].limit = 1; + } + + #if defined(TEST) || defined(INFO) || defined(LIMIT) + *logofs << "Proxy: TOKEN! LIMIT! Setting token [" + << DumpToken(token_split) << "] size to " + << tokens_[token_split].size << " and limit to " + << tokens_[token_split].limit << ".\n" + << logofs_flush; + #endif + + tokens_[token_data].size = control -> TokenSize; + tokens_[token_data].limit = control -> TokenLimit / 4; + + if (tokens_[token_data].limit < 1) + { + tokens_[token_data].limit = 1; + } + + #if defined(TEST) || defined(INFO) || defined(LIMIT) + *logofs << "Proxy: TOKEN! LIMIT! Setting token [" + << DumpToken(token_data) << "] size to " + << tokens_[token_data].size << " and limit to " + << tokens_[token_data].limit << ".\n" + << logofs_flush; + #endif + + for (int i = token_control; i <= token_data; i++) + { + tokens_[i].remaining = tokens_[i].limit; + } + + #if defined(TEST) || defined(INFO) || defined(LIMIT) + *logofs << "Proxy: LIMIT! Using client bitrate " + << "limit " << control -> ClientBitrateLimit + << " server bitrate limit " << control -> + ServerBitrateLimit << " with local limit " + << control -> LocalBitrateLimit << ".\n" + << logofs_flush; + #endif + + // + // Set the other parameters based on + // the token size. + // + + int base = control -> TokenSize; + + control -> SplitDataThreshold = base * 4; + control -> SplitDataPacketLimit = base / 2; + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: LIMIT! Setting split data threshold " + << "to " << control -> SplitDataThreshold + << " split packet limit to " << control -> + SplitDataPacketLimit << " with base " + << base << ".\n" << logofs_flush; + #endif + + // + // Set the number of bytes read from the + // data channels at each loop. This will + // basically determine the maximum band- + // width available for the generic chan- + // nels. + // + + control -> GenericInitialReadSize = base / 2; + control -> GenericMaximumBufferSize = base / 2; + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: LIMIT! Setting generic channel " + << "initial read size to " << control -> + GenericInitialReadSize << " maximum read " + << "size to " << control -> GenericMaximumBufferSize + << " with base " << base << ".\n" + << logofs_flush; + #endif + + return 1; +} + +int Proxy::handleCacheConfiguration() +{ + #ifdef TEST + *logofs << "Proxy: Configuring cache according to pack parameters.\n" + << logofs_flush; + #endif + + // + // Further adjust the cache parameters. If + // packing of the images is enabled, reduce + // the size available for plain images. + // + + if (control -> SessionMode == session_agent) + { + if (control -> PackMethod != NO_PACK) + { + clientStore_ -> getRequestStore(X_PutImage) -> + cacheThreshold = PUTIMAGE_CACHE_THRESHOLD_IF_PACKED; + + clientStore_ -> getRequestStore(X_PutImage) -> + cacheLowerThreshold = PUTIMAGE_CACHE_LOWER_THRESHOLD_IF_PACKED; + } + } + + // + // If this is a shadow session increase the + // size of the image cache. + // + + if (control -> SessionMode == session_shadow) + { + if (control -> PackMethod != NO_PACK) + { + clientStore_ -> getRequestStore(X_NXPutPackedImage) -> + cacheThreshold = PUTPACKEDIMAGE_CACHE_THRESHOLD_IF_PACKED_SHADOW; + + clientStore_ -> getRequestStore(X_NXPutPackedImage) -> + cacheLowerThreshold = PUTPACKEDIMAGE_CACHE_LOWER_THRESHOLD_IF_PACKED_SHADOW; + } + else + { + clientStore_ -> getRequestStore(X_PutImage) -> + cacheThreshold = PUTIMAGE_CACHE_THRESHOLD_IF_SHADOW; + + clientStore_ -> getRequestStore(X_PutImage) -> + cacheLowerThreshold = PUTIMAGE_CACHE_LOWER_THRESHOLD_IF_SHADOW; + } + } + + return 1; +} + +int Proxy::handleSaveStores() +{ + // + // Save content of stores on disk. + // + + char *cacheToAdopt = NULL; + + // + // Set to false the indicator for cumulative store + // size too small + // + bool isTooSmall = false; + + if (control -> PersistentCacheEnableSave) + { + #ifdef TEST + *logofs << "Proxy: Going to save content of client store.\n" + << logofs_flush; + #endif + + cacheToAdopt = handleSaveAllStores(control -> PersistentCachePath, isTooSmall); + } + #ifdef TEST + else + { + if (control -> ProxyMode == proxy_client) + { + *logofs << "Proxy: Saving persistent cache to disk disabled.\n" + << logofs_flush; + } + else + { + *logofs << "Proxy: PANIC! Protocol violation in command save.\n" + << logofs_flush; + + cerr << "Error" << ": Protocol violation in command save.\n"; + + HandleCleanup(); + } + } + #endif + + if (cacheToAdopt != NULL) + { + // + // Do we have a cache already? + // + + if (control -> PersistentCacheName != NULL) + { + // + // Check if old and new cache are the same. + // In this case don't remove the old cache. + // + + if (strcasecmp(control -> PersistentCacheName, cacheToAdopt) != 0) + { + handleResetPersistentCache(); + } + + delete [] control -> PersistentCacheName; + } + + #ifdef TEST + *logofs << "Proxy: Setting current persistent cache file to '" + << cacheToAdopt << "'\n" << logofs_flush; + #endif + + control -> PersistentCacheName = cacheToAdopt; + + return 1; + } + else + { + #ifdef TEST + *logofs << "Proxy: No cache file produced from message stores.\n" + << logofs_flush; + #endif + + // + // It can be that we didn't generate a new cache + // because store was too small or persistent cache + // was disabled. This is not an error. + // + + if (control -> PersistentCacheEnableSave && !isTooSmall) + { + return -1; + } + else + { + return 0; + } + } +} + +int Proxy::handleLoadStores() +{ + // + // Restore the content of the client store + // from disk if a valid cache was negotiated + // at session startup. + // + + if (control -> PersistentCacheEnableLoad == 1 && + control -> PersistentCachePath != NULL && + control -> PersistentCacheName != NULL) + { + #ifdef TEST + *logofs << "Proxy: Going to load content of client store.\n" + << logofs_flush; + #endif + + // + // Returns the same string passed as name of + // the cache, or NULL if it was not possible + // to load the cache from disk. + // + + if (handleLoadAllStores(control -> PersistentCachePath, + control -> PersistentCacheName) == NULL) + { + // + // The corrupted cache should have been + // removed from disk. Get rid of the + // reference so we don't try to delete + // it once again. + // + + if (control -> PersistentCacheName != NULL) + { + delete [] control -> PersistentCacheName; + } + + control -> PersistentCacheName = NULL; + + return -1; + } + + // + // Set timestamp of last time cache + // was loaded from data on disk. + // + + timeouts_.loadTs = getTimestamp(); + + return 1; + } + #ifdef TEST + else + { + if (control -> ProxyMode == proxy_client) + { + *logofs << "Proxy: Loading of cache disabled or no cache file selected.\n" + << logofs_flush; + } + else + { + *logofs << "Proxy: PANIC! Protocol violation in command load.\n" + << logofs_flush; + + cerr << "Error" << ": Protocol violation in command load.\n"; + + HandleCleanup(); + } + } + #endif + + return 0; +} + +int Proxy::handleControl(T_proxy_code code, int data) +{ + // + // Send the given control messages + // to the remote proxy. + // + + #if defined(TEST) || defined(INFO) + + if (data != -1) + { + if (code == code_control_token_reply || + code == code_split_token_reply || + code == code_data_token_reply) + { + *logofs << "Proxy: TOKEN! Sending message '" << DumpControl(code) + << "' at " << strMsTimestamp() << " with count " + << data << ".\n" << logofs_flush; + } + else + { + *logofs << "Proxy: Sending message '" << DumpControl(code) + << "' at " << strMsTimestamp() << " with data ID#" + << data << ".\n" << logofs_flush; + } + } + else + { + *logofs << "Proxy: Sending message '" << DumpControl(code) + << "' at " << strMsTimestamp() << ".\n" + << logofs_flush; + } + + #endif + + // + // Add the control message and see if the + // data has to be flushed immediately. + // + + if (addControlCodes(code, data) < 0) + { + return -1; + } + + switch (code) + { + // + // Append the first data read from the opened + // channel to the control code. + // + + case code_new_x_connection: + case code_new_cups_connection: + case code_new_aux_connection: + case code_new_smb_connection: + case code_new_media_connection: + case code_new_http_connection: + case code_new_font_connection: + case code_new_slave_connection: + + // + // Do we send the token reply immediately? + // The control messages are put at the begin- + // ning of the of the encode buffer, so we may + // reply to multiple tokens before having the + // chance of handling the actual frame data. + // On the other hand, the sooner we reply, the + // sooner the remote proxy is restarted. + // + + case code_control_token_reply: + case code_split_token_reply: + case code_data_token_reply: + { + break; + } + + // + // Also send the congestion control codes + // immediately. + // + // case code_begin_congestion: + // case code_end_congestion: + // + + default: + { + priority_ = 1; + + break; + } + } + + if (priority_ == 1) + { + if (handleFrame(frame_data) < 0) + { + return -1; + } + } + + return 1; +} + +int Proxy::handleSwitch(int channelId) +{ + // + // If data is for a different channel than last + // selected for output, prepend to the data the + // new channel id. + // + + #ifdef DEBUG + *logofs << "Proxy: Requested a switch with " + << "current channel ID#" << outputChannel_ + << " new channel ID#" << channelId << ".\n" + << logofs_flush; + #endif + + if (channelId != outputChannel_) + { + if (needFlush() == 1) + { + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "Proxy: WARNING! Flushing data for the " + << "previous channel ID#" << outputChannel_ + << ".\n" << logofs_flush; + #endif + + if (handleFrame(frame_data) < 0) + { + return -1; + } + } + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Sending message '" + << DumpControl(code_switch_connection) << "' at " + << strMsTimestamp() << " with FD#" << getFd(channelId) + << " channel ID#" << channelId << ".\n" + << logofs_flush; + #endif + + if (addControlCodes(code_switch_connection, channelId) < 0) + { + return -1; + } + + outputChannel_ = channelId; + } + + return 1; +} + +int Proxy::addTokenCodes(T_proxy_token &token) +{ + #if defined(TEST) || defined(INFO) || defined(TOKEN) + *logofs << "Proxy: TOKEN! Sending token [" + << DumpToken(token.type) << "] with " + << token.bytes << " bytes accumulated size " + << token.size << " and " << token.remaining + << " available.\n" << logofs_flush; + #endif + + // + // Give a 'weight' to the token. The tokens + // remaining can become negative if we sent + // a packet that was exceptionally big. + // + + int count = 0; + + // Since ProtoStep7 (#issue 108) + count = token.bytes / token.size; + + // + // Force a count of 1, for example + // if this is a ping. + // + + if (count < 1) + { + count = 1; + + token.bytes = 0; + } + else + { + // Since ProtoStep7 (#issue 108) + if (count > 255) + { + count = 255; + } + + // + // Let the next token account for the + // remaining bytes. + // + + token.bytes %= token.size; + } + + #if defined(TEST) || defined(INFO) || defined(TOKEN) + *logofs << "Proxy: Sending message '" + << DumpControl(token.request) << "' at " + << strMsTimestamp() << " with count " << count + << ".\n" << logofs_flush; + #endif + + controlCodes_[controlLength_++] = 0; + controlCodes_[controlLength_++] = (unsigned char) token.request; + controlCodes_[controlLength_++] = (unsigned char) count; + + statistics -> addFrameOut(); + + token.remaining -= count; + + return 1; +} + +int Proxy::handleToken(T_frame_type type) +{ + #if defined(TEST) || defined(INFO) || defined(TOKEN) + *logofs << "Proxy: TOKEN! Checking tokens with " + << "frame type ["; + + *logofs << (type == frame_ping ? "frame_ping" : "frame_data"); + + *logofs << "] with stream ratio " << statistics -> + getStreamRatio() << ".\n" << logofs_flush; + #endif + + if (type == frame_data) + { + // + // Since ProtoStep7 (#issue 108) + // + + // Send a distinct token for each data type. + // We don't want to slow down the sending of + // the X events, X replies and split confir- + // mation events on the X server side, so + // take care only of the generic data token. + // + + if (control -> ProxyMode == proxy_client) + { + statistics -> updateControlToken(tokens_[token_control].bytes); + + if (tokens_[token_control].bytes > tokens_[token_control].size) + { + if (addTokenCodes(tokens_[token_control]) < 0) + { + return -1; + } + + #if defined(TEST) || defined(INFO) || defined(TOKEN) + + T_proxy_token &token = tokens_[token_control]; + + *logofs << "Proxy: TOKEN! Token class [" + << DumpToken(token.type) << "] has now " + << token.bytes << " bytes accumulated and " + << token.remaining << " tokens remaining.\n" + << logofs_flush; + #endif + } + + statistics -> updateSplitToken(tokens_[token_split].bytes); + + if (tokens_[token_split].bytes > tokens_[token_split].size) + { + if (addTokenCodes(tokens_[token_split]) < 0) + { + return -1; + } + + #if defined(TEST) || defined(INFO) || defined(TOKEN) + + T_proxy_token &token = tokens_[token_split]; + + *logofs << "Proxy: TOKEN! Token class [" + << DumpToken(token.type) << "] has now " + << token.bytes << " bytes accumulated and " + << token.remaining << " tokens remaining.\n" + << logofs_flush; + #endif + } + } + + statistics -> updateDataToken(tokens_[token_data].bytes); + + if (tokens_[token_data].bytes > tokens_[token_data].size) + { + if (addTokenCodes(tokens_[token_data]) < 0) + { + return -1; + } + + #if defined(TEST) || defined(INFO) || defined(TOKEN) + + T_proxy_token &token = tokens_[token_data]; + + *logofs << "Proxy: TOKEN! Token class [" + << DumpToken(token.type) << "] has now " + << token.bytes << " bytes accumulated and " + << token.remaining << " tokens remaining.\n" + << logofs_flush; + #endif + } + } + else + { + if (addTokenCodes(tokens_[token_control]) < 0) + { + return -1; + } + + // + // Reset all counters on a ping. + // + + tokens_[token_control].bytes = 0; + tokens_[token_split].bytes = 0; + tokens_[token_data].bytes = 0; + + #if defined(TEST) || defined(INFO) || defined(TOKEN) + + T_proxy_token &token = tokens_[token_control]; + + *logofs << "Proxy: TOKEN! Token class [" + << DumpToken(token.type) << "] has now " + << token.bytes << " bytes accumulated and " + << token.remaining << " tokens remaining.\n" + << logofs_flush; + #endif + } + + // + // Check if we have entered in + // congestion state. + // + + if (congestion_ == 0 && + tokens_[token_control].remaining <= 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Entering congestion with " + << tokens_[token_control].remaining + << " tokens remaining.\n" << logofs_flush; + #endif + + congestion_ = 1; + } + + statistics -> updateCongestion(tokens_[token_control].remaining, + tokens_[token_control].limit); + + return 1; +} + +int Proxy::handleTokenFromProxy(T_proxy_token &token, int count) +{ + #if defined(TEST) || defined(INFO) || defined(TOKEN) + *logofs << "Proxy: TOKEN! Received token [" + << DumpToken(token.type) << "] request at " + << strMsTimestamp() << " with count " + << count << ".\n" << logofs_flush; + #endif + + // + // Since ProtoStep7 (#issue 108) with no limitations + // concerning invalid token requests at this point + // + + // + // Add our token reply. + // + + if (handleControl(token.reply, count) < 0) + { + return -1; + } + + return 1; +} + +int Proxy::handleTokenReplyFromProxy(T_proxy_token &token, int count) +{ + #if defined(TEST) || defined(INFO) || defined(TOKEN) + *logofs << "Proxy: TOKEN! Received token [" + << DumpToken(token.type) << "] reply at " + << strMsTimestamp() << " with count " << count + << ".\n" << logofs_flush; + #endif + + // + // Since ProtoStep7 (#issue 108) with no limitations + // concerning invalid token requests at this point + // + + // + // Increment the available tokens. + // + + token.remaining += count; + + if (token.remaining > token.limit) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Token overflow handling messages.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Token overflow handling messages.\n"; + + HandleCleanup(); + } + + #if defined(TEST) || defined(INFO) || defined(TOKEN) + *logofs << "Proxy: TOKEN! Token class [" + << DumpToken(token.type) << "] has now " << token.bytes + << " bytes accumulated and " << token.remaining + << " tokens remaining.\n" << logofs_flush; + #endif + + // + // Check if we can jump out of the + // congestion state. + // + + if (congestion_ == 1 && + tokens_[token_control].remaining > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Exiting congestion with " + << tokens_[token_control].remaining + << " tokens remaining.\n" << logofs_flush; + #endif + + congestion_ = 0; + } + + statistics -> updateCongestion(tokens_[token_control].remaining, + tokens_[token_control].limit); + + return 1; +} + +void Proxy::handleFailOnSave(const char *fullName, const char *failContext) const +{ + #ifdef WARNING + *logofs << "Proxy: WARNING! Error saving stores to cache file " + << "in context [" << failContext << "].\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Error saving stores to cache file " + << "in context [" << failContext << "].\n"; + + #ifdef WARNING + *logofs << "Proxy: WARNING! Removing invalid cache '" + << fullName << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Removing invalid cache '" + << fullName << "'.\n"; + + unlink(fullName); +} + +void Proxy::handleFailOnLoad(const char *fullName, const char *failContext) const +{ + #ifdef WARNING + *logofs << "Proxy: WARNING! Error loading stores from cache file " + << "in context [" << failContext << "].\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Error loading stores from cache file " + << "in context [" << failContext << "].\n"; + + #ifdef WARNING + *logofs << "Proxy: WARNING! Removing invalid cache '" + << fullName << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Removing invalid cache '" + << fullName << "'.\n"; + + unlink(fullName); +} + +int Proxy::handleSaveVersion(unsigned char *buffer, int &major, + int &minor, int &patch) const +{ + // Since ProtoStep8 (#issue 108) + major = 3; + minor = 0; + patch = 0; + + *(buffer + 0) = major; + *(buffer + 1) = minor; + + PutUINT(patch, buffer + 2, storeBigEndian()); + + return 1; +} + +int Proxy::handleLoadVersion(const unsigned char *buffer, int &major, + int &minor, int &patch) const +{ + major = *(buffer + 0); + minor = *(buffer + 1); + + patch = GetUINT(buffer + 2, storeBigEndian()); + + // + // Force the proxy to discard the + // incompatible caches. + // + + // Since ProtoStep8 (#issue 108) + if (major < 3) + { + return -1; + } + + return 1; +} + +char *Proxy::handleSaveAllStores(const char *savePath, bool & isTooSmall) const +{ + isTooSmall = false; + + int cumulativeSize = MessageStore::getCumulativeTotalStorageSize(); + + if (cumulativeSize < control -> PersistentCacheThreshold) + { + #ifdef TEST + *logofs << "Proxy: Cache not saved as size is " + << cumulativeSize << " with threshold set to " + << control -> PersistentCacheThreshold + << ".\n" << logofs_flush; + #endif + + // + // Cumulative store size is smaller than threshold + // so the indicator is set to true + // + + isTooSmall = true; + + return NULL; + } + else if (savePath == NULL) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! No name provided for save path.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": No name provided for save path.\n"; + + return NULL; + } + + #ifdef TEST + *logofs << "Proxy: Going to save content of message stores.\n" + << logofs_flush; + #endif + + // + // Our parent process is likely going to terminate. + // Until we finish saving cache we must ignore its + // SIGIPE. + // + + DisableSignals(); + + ofstream *cachefs = NULL; + + md5_state_t *md5StateStream = NULL; + md5_byte_t *md5DigestStream = NULL; + + md5_state_t *md5StateClient = NULL; + md5_byte_t *md5DigestClient = NULL; + + char md5String[MD5_LENGTH * 2 + 2]; + + char fullName[strlen(savePath) + MD5_LENGTH * 2 + 4]; + + // + // Prepare the template for the temporary file + // + + const char* const uniqueTemplate = "XXXXXX"; + char tempName[strlen(savePath) + strlen("/") + 4 + strlen(uniqueTemplate) + 1]; + + snprintf(tempName, sizeof tempName, "%s/%s%s", + savePath, + control -> ProxyMode == proxy_client ? + "Z-C-" : + "Z-S-", + uniqueTemplate); + + #ifdef TEST + *logofs << "Proxy: Generating temporary file with template '" + << tempName << "'.\n" << logofs_flush; + #endif + + // + // Change the mask to make the file only + // readable by the user, then restore the + // old mask. + // + + mode_t fileMode = umask(0077); + + // + // Generate a unique temporary filename from tempName + // and then create and open the file + // + + int fdTemp = mkstemp(tempName); + if (fdTemp == -1) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Can't create temporary file in '" + << savePath << "'. Cause = " << strerror(errno) << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't create temporary file in '" + << savePath << "'. Cause = " << strerror(errno) << ".\n"; + + umask(fileMode); + + EnableSignals(); + + return NULL; + } + + #ifdef TEST + *logofs << "Proxy: Saving cache to file '" + << tempName << "'.\n" << logofs_flush; + #endif + + // + // Create and open the output stream for the new temporary + // file + // + + cachefs = new (std::nothrow) ofstream(tempName, ios::out | ios::binary); + if ((cachefs == NULL) || cachefs->fail()) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Can't create stream for temporary file '" + << tempName << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't create stream for temporary file '" + << tempName << "'.\n"; + + close(fdTemp); + unlink(tempName); + + umask(fileMode); + + EnableSignals(); + + return NULL; + } + + // + // Close the file descriptor returned by mkstemp + // and restore the old mask + // + + close(fdTemp); + umask(fileMode); + + md5StateStream = new md5_state_t(); + md5DigestStream = new md5_byte_t[MD5_LENGTH]; + + md5_init(md5StateStream); + + // + // First write the proxy version. + // + + unsigned char version[4]; + + int major; + int minor; + int patch; + + handleSaveVersion(version, major, minor, patch); + + #ifdef TEST + *logofs << "Proxy: Saving cache using version '" + << major << "." << minor << "." << patch + << "'.\n" << logofs_flush; + #endif + + if (PutData(cachefs, version, 4) < 0) + { + handleFailOnSave(tempName, "A"); + + delete cachefs; + + delete md5StateStream; + delete [] md5DigestStream; + + EnableSignals(); + + return NULL; + } + + // + // Make space for the calculated MD5 so we + // can later rewind the file and write it + // at this position. + // + + if (PutData(cachefs, md5DigestStream, MD5_LENGTH) < 0) + { + handleFailOnSave(tempName, "B"); + + delete cachefs; + + delete md5StateStream; + delete [] md5DigestStream; + + EnableSignals(); + + return NULL; + } + + md5StateClient = new md5_state_t(); + md5DigestClient = new md5_byte_t[MD5_LENGTH]; + + md5_init(md5StateClient); + + #ifdef DUMP + + ofstream *cacheDump = NULL; + + ofstream *tempfs = (ofstream*) logofs; + + char cacheDumpName[DEFAULT_STRING_LENGTH]; + + if (control -> ProxyMode == proxy_client) + { + snprintf(cacheDumpName, DEFAULT_STRING_LENGTH - 1, + "%s/client-cache-dump", control -> TempPath); + } + else + { + snprintf(cacheDumpName, DEFAULT_STRING_LENGTH - 1, + "%s/server-cache-dump", control -> TempPath); + } + + *(cacheDumpName + DEFAULT_STRING_LENGTH - 1) = '\0'; + + fileMode = umask(0077); + + cacheDump = new ofstream(cacheDumpName, ios::out); + + umask(fileMode); + + logofs = cacheDump; + + #endif + + // + // Use the virtual method of the concrete proxy class. + // + + int allSaved = handleSaveAllStores(cachefs, md5StateStream, md5StateClient); + + #ifdef DUMP + + logofs = tempfs; + + delete cacheDump; + + #endif + + if (allSaved == -1) + { + handleFailOnSave(tempName, "C"); + + delete cachefs; + + delete md5StateStream; + delete [] md5DigestStream; + + delete md5StateClient; + delete [] md5DigestClient; + + EnableSignals(); + + return NULL; + } + + md5_finish(md5StateClient, md5DigestClient); + + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + sprintf(md5String + (i * 2), "%02X", md5DigestClient[i]); + } + + strcpy(fullName, (control -> ProxyMode == proxy_client) ? "C-" : "S-"); + + strcat(fullName, md5String); + + md5_append(md5StateStream, (const md5_byte_t *) fullName, strlen(fullName)); + md5_finish(md5StateStream, md5DigestStream); + + // + // Go to the beginning of file plus + // the integer where we wrote our + // proxy version. + // + + cachefs -> seekp(4); + + if (PutData(cachefs, md5DigestStream, MD5_LENGTH) < 0) + { + handleFailOnSave(tempName, "D"); + + delete cachefs; + + delete md5StateStream; + delete [] md5DigestStream; + + delete md5StateClient; + delete [] md5DigestClient; + + EnableSignals(); + + return NULL; + } + + delete cachefs; + + // + // Copy the resulting cache name without + // the path so that we can return it to + // the caller. + // + + char *cacheName = new char[MD5_LENGTH * 2 + 4]; + + strcpy(cacheName, fullName); + + // + // Add the path to the full name and move + // the cache into the path. + // + + strcpy(fullName, savePath); + strcat(fullName, (control -> ProxyMode == proxy_client) ? "/C-" : "/S-"); + strcat(fullName, md5String); + + #ifdef TEST + *logofs << "Proxy: Renaming cache file from '" + << tempName << "' to '" << fullName + << "'.\n" << logofs_flush; + #endif + + rename(tempName, fullName); + + delete md5StateStream; + delete [] md5DigestStream; + + delete md5StateClient; + delete [] md5DigestClient; + + // + // Restore the original handlers. + // + + EnableSignals(); + + #ifdef TEST + *logofs << "Proxy: Successfully saved cache file '" + << cacheName << "'.\n" << logofs_flush; + #endif + + // + // This must be enabled only for test + // because it requires that client and + // server reside on the same machine. + // + + if (control -> PersistentCacheCheckOnShutdown == 1 && + control -> ProxyMode == proxy_server) + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: MATCH! Checking if the file '" + << fullName << "' matches a client cache.\n" + << logofs_flush; + #endif + + strcpy(fullName, savePath); + strcat(fullName, "/C-"); + strcat(fullName, md5String); + + struct stat fileStat; + + if (stat(fullName, &fileStat) != 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Can't find a client cache " + << "with name '" << fullName << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't find a client cache " + << "with name '" << fullName << "'.\n"; + + HandleShutdown(); + } + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: MATCH! Client cache '" << fullName + << "' matches the local cache.\n" + << logofs_flush; + #endif + } + + return cacheName; +} + +const char *Proxy::handleLoadAllStores(const char *loadPath, const char *loadName) const +{ + #ifdef TEST + *logofs << "Proxy: Going to load content of message stores.\n" + << logofs_flush; + #endif + + // + // Until we finish loading cache we + // must at least ignore any SIGIPE. + // + + DisableSignals(); + + if (loadPath == NULL || loadName == NULL) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! No path or no file name provided for cache to restore.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": No path or no file name provided for cache to restore.\n"; + + EnableSignals(); + + return NULL; + } + else if (strlen(loadName) != MD5_LENGTH * 2 + 2) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Bad file name provided for cache to restore.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Bad file name provided for cache to restore.\n"; + + EnableSignals(); + + return NULL; + } + + istream *cachefs = NULL; + char md5String[(MD5_LENGTH * 2) + 2]; + md5_byte_t md5FromFile[MD5_LENGTH]; + + char *cacheName = new char[strlen(loadPath) + strlen(loadName) + 3]; + + strcpy(cacheName, loadPath); + strcat(cacheName, "/"); + strcat(cacheName, loadName); + + #ifdef TEST + *logofs << "Proxy: Name of cache file is '" + << cacheName << "'.\n" << logofs_flush; + #endif + + cachefs = new ifstream(cacheName, ios::in | ios::binary); + + unsigned char version[4]; + + if (cachefs == NULL || GetData(cachefs, version, 4) < 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Can't read cache file '" + << cacheName << "'.\n" << logofs_flush;; + #endif + + handleFailOnLoad(cacheName, "A"); + + delete cachefs; + + delete [] cacheName; + + EnableSignals(); + + return NULL; + } + + int major; + int minor; + int patch; + + if (handleLoadVersion(version, major, minor, patch) < 0) + { + #ifdef PANIC + *logofs << "Proxy: WARNING! Incompatible version '" + << major << "." << minor << "." << patch + << "' in cache file '" << cacheName + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Incompatible version '" + << major << "." << minor << "." << patch + << "' in cache file '" << cacheName + << "'.\n" << logofs_flush; + + if (control -> ProxyMode == proxy_server) + { + handleFailOnLoad(cacheName, "B"); + } + else + { + // + // Simply remove the cache file. + // + + unlink(cacheName); + } + + delete cachefs; + + delete [] cacheName; + + EnableSignals(); + + return NULL; + } + + #ifdef TEST + *logofs << "Proxy: Reading from cache file version '" + << major << "." << minor << "." << patch + << "'.\n" << logofs_flush; + #endif + + if (GetData(cachefs, md5FromFile, MD5_LENGTH) < 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! No checksum in cache file '" + << loadName << "'.\n" << logofs_flush; + #endif + + handleFailOnLoad(cacheName, "C"); + + delete cachefs; + + delete [] cacheName; + + EnableSignals(); + + return NULL; + } + + md5_state_t *md5StateStream = NULL; + md5_byte_t *md5DigestStream = NULL; + + md5StateStream = new md5_state_t(); + md5DigestStream = new md5_byte_t[MD5_LENGTH]; + + md5_init(md5StateStream); + + // + // Use the virtual method of the proxy class. + // + + if (handleLoadAllStores(cachefs, md5StateStream) < 0) + { + handleFailOnLoad(cacheName, "D"); + + delete cachefs; + + delete md5StateStream; + delete [] md5DigestStream; + + delete [] cacheName; + + EnableSignals(); + + return NULL; + } + + md5_append(md5StateStream, (const md5_byte_t *) loadName, strlen(loadName)); + md5_finish(md5StateStream, md5DigestStream); + + for (int i = 0; i < MD5_LENGTH; i++) + { + if (md5DigestStream[i] != md5FromFile[i]) + { + #ifdef PANIC + + *logofs << "Proxy: PANIC! Bad checksum for cache file '" + << cacheName << "'.\n" << logofs_flush; + + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + sprintf(md5String + (i * 2), "%02X", md5FromFile[i]); + } + + *logofs << "Proxy: PANIC! Saved checksum is '" + << md5String << "'.\n" << logofs_flush; + + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + sprintf(md5String + (i * 2),"%02X", md5DigestStream[i]); + } + + *logofs << "Proxy: PANIC! Calculated checksum is '" + << md5String << "'.\n" << logofs_flush; + + #endif + + handleFailOnLoad(cacheName, "E"); + + delete cachefs; + + delete md5StateStream; + delete [] md5DigestStream; + + delete [] cacheName; + + EnableSignals(); + + return NULL; + } + } + + delete cachefs; + + delete md5StateStream; + delete [] md5DigestStream; + + delete [] cacheName; + + // + // Restore the original handlers. + // + + EnableSignals(); + + #ifdef TEST + *logofs << "Proxy: Successfully loaded cache file '" + << loadName << "'.\n" << logofs_flush; + #endif + + // + // Return the string provided by caller. + // + + return loadName; +} + +int Proxy::allocateChannelMap(int fd) +{ + // + // We assume that the fd is lower than + // the maximum allowed number. This is + // checked at the time the connection + // is accepted. + // + + if (fd < 0 || fd >= CONNECTIONS_LIMIT) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Internal error allocating " + << "new channel with FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Internal error allocating " + << "new channel with FD#" << fd_ << ".\n"; + + HandleCleanup(); + } + + for (int channelId = 0; + channelId < CONNECTIONS_LIMIT; + channelId++) + { + if (checkLocalChannelMap(channelId) == 1 && + fdMap_[channelId] == -1) + { + fdMap_[channelId] = fd; + channelMap_[fd] = channelId; + + #ifdef TEST + *logofs << "Proxy: Allocated new channel ID#" + << channelId << " with FD#" << fd << ".\n" + << logofs_flush; + #endif + + return channelId; + } + } + + // + // No available channel is remaining. + // + + #ifdef TEST + *logofs << "Proxy: WARNING! Can't allocate a new channel " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + return -1; +} + +int Proxy::checkChannelMap(int channelId) +{ + // + // To be acceptable, the channel id must + // be an id that is not possible to use + // to allocate channels at this side. + // + + if (checkLocalChannelMap(channelId) == 1) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Can't open a new channel " + << "with invalid ID#" << channelId << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't open a new channel " + << "with invalid ID#" << channelId << ".\n"; + + return -1; + } + else if (channels_[channelId] != NULL) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Can't open a new channel " + << "over an existing ID#" << channelId + << " with FD#" << getFd(channelId) + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't open a new channel " + << "over an existing ID#" << channelId + << " with FD#" << getFd(channelId) + << ".\n"; + + return -1; + } + + return 1; +} + +int Proxy::assignChannelMap(int channelId, int fd) +{ + // + // We assume that the fd is lower than + // the maximum allowed number. This is + // checked at the time the connection + // is accepted. + // + + if (channelId < 0 || channelId >= CONNECTIONS_LIMIT || + fd < 0 || fd >= CONNECTIONS_LIMIT) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Internal error assigning " + << "new channel with FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Internal error assigning " + << "new channel with FD#" << fd_ << ".\n"; + + HandleCleanup(); + } + + fdMap_[channelId] = fd; + channelMap_[fd] = channelId; + + return 1; +} + +void Proxy::cleanupChannelMap(int channelId) +{ + int fd = fdMap_[channelId]; + + if (fd != -1) + { + fdMap_[channelId] = -1; + channelMap_[fd] = -1; + } +} + +int Proxy::addControlCodes(T_proxy_code code, int data) +{ + // + // Flush the encode buffer plus all the outstanding + // control codes if there is not enough space for + // the new control message. We need to ensure that + // there are further bytes available, in the case + // we will need to add more token control messages. + // + + if (controlLength_ + 3 > CONTROL_CODES_THRESHOLD) + { + #ifdef WARNING + *logofs << "Proxy: WARNING! Flushing control messages " + << "while sending code '" << DumpControl(code) + << "'.\n" << logofs_flush; + #endif + + if (handleFlush() < 0) + { + return -1; + } + } + + controlCodes_[controlLength_++] = 0; + controlCodes_[controlLength_++] = (unsigned char) code; + controlCodes_[controlLength_++] = (unsigned char) (data == -1 ? 0 : data); + + // + // Account for the control frame. + // + + statistics -> addFrameOut(); + + return 1; +} + +void Proxy::setSplitTimeout(int channelId) +{ + int needed = channels_[channelId] -> needSplit(); + + if (needed != isTimestamp(timeouts_.splitTs)) + { + if (needed == 1) + { + #if defined(TEST) || defined(INFO) || defined(SPLIT) + *logofs << "Proxy: SPLIT! Allocating split timestamp at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + timeouts_.splitTs = getTimestamp(); + } + else + { + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] != NULL && + channels_[channelId] -> needSplit() == 1) + { + #ifdef TEST + *logofs << "Proxy: SPLIT! Channel for FD#" + << getFd(channelId) << " still needs splits.\n" + << logofs_flush; + #endif + + return; + } + } + + #if defined(TEST) || defined(INFO) || defined(SPLIT) + *logofs << "Proxy: SPLIT! Resetting split timestamp at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + timeouts_.splitTs = nullTimestamp(); + } + } +} + +void Proxy::setMotionTimeout(int channelId) +{ + int needed = channels_[channelId] -> needMotion(); + + if (needed != isTimestamp(timeouts_.motionTs)) + { + if (channels_[channelId] -> needMotion() == 1) + { + #if defined(TEST) || defined(INFO) || defined(SPLIT) + *logofs << "Proxy: Allocating motion timestamp at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + timeouts_.motionTs = getTimestamp(); + } + else + { + T_list &channelList = activeChannels_.getList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] != NULL && + channels_[channelId] -> needMotion() == 1) + { + #ifdef TEST + *logofs << "Proxy: SPLIT! Channel for FD#" + << getFd(channelId) << " still needs motions.\n" + << logofs_flush; + #endif + + return; + } + } + + #if defined(TEST) || defined(INFO) || defined(SPLIT) + *logofs << "Proxy: Resetting motion timestamp at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + timeouts_.motionTs = nullTimestamp(); + } + } +} + +void Proxy::increaseChannels(int channelId) +{ + #ifdef TEST + *logofs << "Proxy: Adding channel " << channelId + << " to the list of active channels.\n" + << logofs_flush; + #endif + + activeChannels_.add(channelId); + + #ifdef TEST + *logofs << "Proxy: There are " << activeChannels_.getSize() + << " allocated channels for proxy FD#" << fd_ + << ".\n" << logofs_flush; + #endif +} + +void Proxy::decreaseChannels(int channelId) +{ + #ifdef TEST + *logofs << "Proxy: Removing channel " << channelId + << " from the list of active channels.\n" + << logofs_flush; + #endif + + activeChannels_.remove(channelId); + + #ifdef TEST + *logofs << "Proxy: There are " << activeChannels_.getSize() + << " allocated channels for proxy FD#" << fd_ + << ".\n" << logofs_flush; + #endif +} + +int Proxy::allocateTransport(int channelFd, int channelId) +{ + if (transports_[channelId] == NULL) + { + transports_[channelId] = new Transport(channelFd); + + if (transports_[channelId] == NULL) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Can't allocate transport for " + << "channel id " << channelId << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate transport for " + << "channel id " << channelId << ".\n"; + + return -1; + } + } + else if (transports_[channelId] -> + getType() != transport_agent) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Transport for channel id " + << channelId << " should be null.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Transport for channel id " + << channelId << " should be null.\n"; + + return -1; + } + + return 1; +} + +int Proxy::deallocateTransport(int channelId) +{ + // + // Transport for the agent connection + // is passed from the outside when + // creating the channel. + // + + if (transports_[channelId] -> + getType() != transport_agent) + { + delete transports_[channelId]; + } + + transports_[channelId] = NULL; + + return 1; +} + +int Proxy::handleNewGenericConnection(int clientFd, T_channel_type type, const char *label) +{ + int channelId = allocateChannelMap(clientFd); + + if (channelId == -1) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Maximum number of available " + << "channels exceeded.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Maximum number of available " + << "channels exceeded.\n"; + + return -1; + } + + #ifdef TEST + *logofs << "Proxy: Channel for " << label << " descriptor " + << "FD#" << clientFd << " mapped to ID#" + << channelId << ".\n" + << logofs_flush; + #endif + + // + // Turn queuing off for path server-to-proxy. + // + + SetNoDelay(clientFd, 1); + + if (allocateTransport(clientFd, channelId) < 0) + { + return -1; + } + + switch (type) + { + case channel_cups: + { + channels_[channelId] = new CupsChannel(transports_[channelId], compressor_); + + break; + } + case channel_smb: + { + channels_[channelId] = new SmbChannel(transports_[channelId], compressor_); + + break; + } + case channel_media: + { + channels_[channelId] = new MediaChannel(transports_[channelId], compressor_); + + break; + } + case channel_http: + { + channels_[channelId] = new HttpChannel(transports_[channelId], compressor_); + + break; + } + case channel_font: + { + channels_[channelId] = new FontChannel(transports_[channelId], compressor_); + + break; + } + default: + { + channels_[channelId] = new SlaveChannel(transports_[channelId], compressor_); + + break; + } + } + + if (channels_[channelId] == NULL) + { + deallocateTransport(channelId); + + return -1; + } + + #ifdef TEST + *logofs << "Proxy: Accepted new connection to " + << label << " server.\n" << logofs_flush; + #endif + + cerr << "Info" << ": Accepted new connection to " + << label << " server.\n"; + + increaseChannels(channelId); + + switch (type) + { + case channel_cups: + { + if (handleControl(code_new_cups_connection, channelId) < 0) + { + return -1; + } + + break; + } + case channel_smb: + { + if (handleControl(code_new_smb_connection, channelId) < 0) + { + return -1; + } + + break; + } + case channel_media: + { + if (handleControl(code_new_media_connection, channelId) < 0) + { + return -1; + } + + break; + } + case channel_http: + { + if (handleControl(code_new_http_connection, channelId) < 0) + { + return -1; + } + + break; + } + case channel_font: + { + if (handleControl(code_new_font_connection, channelId) < 0) + { + return -1; + } + + break; + } + default: + { + if (handleControl(code_new_slave_connection, channelId) < 0) + { + return -1; + } + + break; + } + } + + channels_[channelId] -> handleConfiguration(); + + return 1; +} + +int Proxy::handleNewSlaveConnection(int clientFd) +{ + // Since ProtoStep7 (#issue 108) + return handleNewGenericConnection(clientFd, channel_slave, "slave"); +} + + + +int Proxy::handleNewGenericConnectionFromProxy(int channelId, T_channel_type type, + ChannelEndPoint &endPoint, const char *label) +{ + char *unixPath, *host; + long port; + + if (endPoint.getUnixPath(&unixPath)) { + return handleNewGenericConnectionFromProxyUnix(channelId, type, unixPath, label); + } + + if (endPoint.getTCPHostAndPort(&host, &port)) { + return handleNewGenericConnectionFromProxyTCP(channelId, type, host, port, label); + } + + #ifdef WARNING + *logofs << "Proxy: WARNING! Refusing attempted connection " + << "to " << label << " server.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Refusing attempted connection " + << "to " << label << " server.\n"; + + return -1; +} + +int Proxy::handleNewGenericConnectionFromProxyTCP(int channelId, T_channel_type type, + const char *hostname, long port, const char *label) + +{ + if (port <= 0) + { + // + // This happens when user has disabled + // forwarding of the specific service. + // + + #ifdef WARNING + *logofs << "Proxy: WARNING! Refusing attempted connection " + << "to " << label << " server.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Refusing attempted connection " + << "to " << label << " server.\n"; + + return -1; + } + + const char *serverHost = hostname; + int serverAddrFamily = AF_INET; + sockaddr *serverAddr = NULL; + unsigned int serverAddrLength = 0; + + #ifdef TEST + *logofs << "Proxy: Connecting to " << label + << " server '" << serverHost << "' on TCP port '" + << port << "'.\n" << logofs_flush; + #endif + + int serverIPAddr = GetHostAddress(serverHost); + + if (serverIPAddr == 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Unknown " << label + << " server host '" << serverHost << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Unknown " << label + << " server host '" << serverHost + << "'.\n"; + + return -1; + } + + sockaddr_in *serverAddrTCP = new sockaddr_in; + + serverAddrTCP -> sin_family = AF_INET; + serverAddrTCP -> sin_port = htons(port); + serverAddrTCP -> sin_addr.s_addr = serverIPAddr; + + serverAddr = (sockaddr *) serverAddrTCP; + serverAddrLength = sizeof(sockaddr_in); + + // + // Connect to the requested server. + // + + int serverFd = socket(serverAddrFamily, SOCK_STREAM, PF_UNSPEC); + + if (serverFd < 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Call to socket failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to socket failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + delete serverAddrTCP; + + return -1; + } + else if (connect(serverFd, serverAddr, serverAddrLength) < 0) + { + #ifdef WARNING + *logofs << "Proxy: WARNING! Connection to " << label + << " server '" << serverHost << ":" << port + << "' failed with error '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Connection to " << label + << " server '" << serverHost << ":" << port + << "' failed with error '" << ESTR() << "'.\n"; + + close(serverFd); + + delete serverAddrTCP; + + return -1; + } + + delete serverAddrTCP; + + if (handlePostConnectionFromProxy(channelId, serverFd, type, label) < 0) + { + return -1; + } + + #ifdef TEST + *logofs << "Proxy: Forwarded new connection to " + << label << " server on port '" << port + << "'.\n" << logofs_flush; + #endif + + cerr << "Info" << ": Forwarded new connection to " + << label << " server on port '" << port + << "'.\n"; + + return 1; +} + +int Proxy::handleNewGenericConnectionFromProxyUnix(int channelId, T_channel_type type, + const char *path, const char *label) +{ + if (path == NULL || *path == '\0' ) + { + // + // This happens when user has disabled + // forwarding of the specific service. + // + + #ifdef WARNING + *logofs << "Proxy: WARNING! Refusing attempted connection " + << "to " << label << " server.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Refusing attempted connection " + << "to " << label << " server.\n"; + + return -1; + } + + sockaddr_un serverAddrUnix; + + unsigned int serverAddrLength = sizeof(sockaddr_un); + + int serverAddrFamily = AF_UNIX; + + serverAddrUnix.sun_family = AF_UNIX; + + const int serverAddrNameLength = 108; + + strncpy(serverAddrUnix.sun_path, path, serverAddrNameLength); + + *(serverAddrUnix.sun_path + serverAddrNameLength - 1) = '\0'; + + #ifdef TEST + *logofs << "Proxy: Connecting to " << label << " server " + << "on Unix port '" << path << "'.\n" << logofs_flush; + #endif + + // + // Connect to the requested server. + // + + int serverFd = socket(serverAddrFamily, SOCK_STREAM, PF_UNSPEC); + + if (serverFd < 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! Call to socket failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to socket failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + return -1; + } + else if (connect(serverFd, (sockaddr *) &serverAddrUnix, serverAddrLength) < 0) + { + #ifdef WARNING + *logofs << "Proxy: WARNING! Connection to " << label + << " server on Unix port '" << path << "' failed " + << "with error " << EGET() << ", '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Connection to " << label + << " server on Unix port '" << path << "' failed " + << "with error " << EGET() << ", '" << ESTR() << "'.\n"; + + close(serverFd); + + return -1; + } + + if (handlePostConnectionFromProxy(channelId, serverFd, type, label) < 0) + { + return -1; + } + + #ifdef TEST + *logofs << "Proxy: Forwarded new connection to " + << label << " server on Unix port '" << path + << "'.\n" << logofs_flush; + #endif + + cerr << "Info" << ": Forwarded new connection to " + << label << " server on Unix port '" << path + << "'.\n"; + + return 1; +} + +int Proxy::handleNewSlaveConnectionFromProxy(int channelId) +{ + + cerr << "Info" << ": New slave connection on " + << "channel ID#" << channelId << "\n"; + + char *nx_slave_cmd = getenv("NX_SLAVE_CMD"); + if (nx_slave_cmd == NULL) { + return -1; + } + + int spair[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, spair) == -1) { + perror("socketpair"); + return -1; + } + + int serverFd = spair[0]; + int clientFd = spair[1]; + + if (handlePostConnectionFromProxy(channelId, serverFd, channel_slave, "slave") < 0) + { + close(serverFd); + close(clientFd); + return -1; + } + + + int pid = fork(); + if (pid == 0) + { + + if (dup2(clientFd, 0) == -1) + { + perror("dup2"); + exit(1); + } + + if (dup2(clientFd, 1) == -1) + { + perror("dup2"); + exit(1); + } + + close(serverFd); + close(clientFd); + + /* Close FDs used by NX, QVD #1208 */ + for (int fd = 3; fd < 256; fd++) { + close(fd); + } + + char *const argv[2] = {nx_slave_cmd, NULL}; + + if (execv(nx_slave_cmd, argv) == -1) + { + perror("execv"); + } + exit(1); + + } + else if (pid == -1) + { + // TODO Test this! + perror("fork"); + close(serverFd); + close(clientFd); + return -1; + } + + close(clientFd); + slavePidMap_[channelId] = pid; + + cerr << "Info" << ": slave channel ID#" << channelId << " handler has PID " << pid << endl; + + return 1; +} + +void Proxy::checkSlaves() +{ + for (int channelId = 0; channelId 1 && HandleChild(pid)) + { + slavePidMap_[channelId] = nothing; + cerr << "Info:" << " Handled death of slave with pid " << pid << endl; + } + } +} + +int Proxy::handlePostConnectionFromProxy(int channelId, int serverFd, + T_channel_type type, const char *label) +{ + // + // Turn queuing off for path proxy-to-server. + // + + SetNoDelay(serverFd, 1); + + assignChannelMap(channelId, serverFd); + + #ifdef TEST + *logofs << "Proxy: Descriptor FD#" << serverFd + << " mapped to channel ID#" << channelId << ".\n" + << logofs_flush; + #endif + + if (allocateTransport(serverFd, channelId) < 0) + { + return -1; + } + + switch (type) + { + case channel_cups: + { + channels_[channelId] = new CupsChannel(transports_[channelId], compressor_); + break; + } + case channel_smb: + { + channels_[channelId] = new SmbChannel(transports_[channelId], compressor_); + + break; + } + case channel_media: + { + channels_[channelId] = new MediaChannel(transports_[channelId], compressor_); + + break; + } + case channel_http: + { + channels_[channelId] = new HttpChannel(transports_[channelId], compressor_); + + break; + } + case channel_font: + { + channels_[channelId] = new FontChannel(transports_[channelId], compressor_); + + break; + } + default: + { + channels_[channelId] = new SlaveChannel(transports_[channelId], compressor_); + + break; + } + } + + if (channels_[channelId] == NULL) + { + deallocateTransport(channelId); + + return -1; + } + + increaseChannels(channelId); + + channels_[channelId] -> handleConfiguration(); + + return 1; +} diff --git a/nxcomp/src/Proxy.h b/nxcomp/src/Proxy.h new file mode 100644 index 000000000..ea60c827a --- /dev/null +++ b/nxcomp/src/Proxy.h @@ -0,0 +1,1276 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Proxy_H +#define Proxy_H + +#include + +#ifdef _AIX +#include +#endif + +#include "Misc.h" +#include "Timestamp.h" + +#include "List.h" +#include "Channel.h" +#include "Transport.h" +#include "EncodeBuffer.h" +#include "ProxyReadBuffer.h" +#include "ChannelEndPoint.h" + +// +// Forward declaration as we +// need a pointer. +// + +class Agent; + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Log the important tracepoints related +// to writing packets to the peer proxy. +// + +#undef FLUSH + +// +// Codes used for control messages in +// proxy-to-proxy protocol. +// +// The following codes are currently +// unused. +// +// code_alert_reply, +// code_reset_request, +// code_reset_reply, +// code_load_reply, +// code_save_reply, +// code_shutdown_reply, +// code_configuration_request, +// code_configuration_reply. +// +// These are for compatibility with +// old versions. +// +// code_sync_request, +// code_sync_reply, +// +// The code_new_aux_connection should not +// be used anymore. Auxiliary X connections +// are treated as normal X channels since +// version 1.5.0. +// + +typedef enum +{ + code_new_x_connection, + code_new_cups_connection, + code_new_aux_connection, + code_new_smb_connection, + code_new_media_connection, + code_switch_connection, + code_drop_connection, + code_finish_connection, + code_begin_congestion, + code_end_congestion, + code_alert_request, + code_alert_reply, + code_reset_request, + code_reset_reply, + code_load_request, + code_load_reply, + code_save_request, + code_save_reply, + code_shutdown_request, + code_shutdown_reply, + code_control_token_request, + code_control_token_reply, + code_configuration_request, + code_configuration_reply, + code_statistics_request, + code_statistics_reply, + code_new_http_connection, + code_sync_request, + code_sync_reply, + code_new_font_connection, + code_new_slave_connection, + code_finish_listeners, + code_split_token_request, + code_split_token_reply, + code_data_token_request, + code_data_token_reply, + code_last_tag + +} T_proxy_code; + +typedef enum +{ + operation_in_negotiation, + operation_in_messages, + operation_in_configuration, + operation_in_statistics, + operation_last_tag + +} T_proxy_operation; + +typedef enum +{ + frame_ping, + frame_data, + +} T_frame_type; + +typedef enum +{ + token_control, + token_split, + token_data + +} T_token_type; + +typedef enum +{ + load_if_any, + load_if_first + +} T_load_type; + +class Proxy +{ + public: + + // + // Maximum number of supported channels. + // + + static const int CONNECTIONS_LIMIT = 256; + + // + // Numboer of token types. + // + + static const int TOKEN_TYPES = 3; + + // + // Lenght of buffer we use to add our + // control messages plus the length of + // the data frame. + // + + static const int CONTROL_CODES_LENGTH = ENCODE_BUFFER_PREFIX_SIZE - 5; + + static const int CONTROL_CODES_THRESHOLD = CONTROL_CODES_LENGTH - 9; + + Proxy(int fd); + + virtual ~Proxy(); + + // + // Inform the proxy that the negotiation phase is + // completed and that it can start handling binary + // messages. + // + + int setOperational(); + + int getOperational() + { + return (operation_ != operation_in_negotiation); + } + + int setReadDescriptors(fd_set *fdSet, int &fdMax, T_timestamp &tsMax); + + int setWriteDescriptors(fd_set *fdSet, int &fdMax, T_timestamp &tsMax); + + // + // Perform the operation on the proxy + // link or its own channels. + // + + int handleRead(int &resultFds, fd_set &fdSet); + + int handleFlush(int &resultFds, fd_set &fdSet); + + int handleRead(); + + int handleRead(int fd, const char *data = NULL, int size = 0); + + int handleEvents(); + + int handleFlush(); + + int handleFlush(int fd); + + int handlePing(); + + int handleFinish(); + + int handleShutdown(); + + int handleStatistics(int type, ostream *statofs); + + int handleAlert(int alert); + + int handleRotate() + { + activeChannels_.rotate(); + + return 1; + } + + int handleChannelConfiguration(); + + int handleSocketConfiguration(); + + int handleLinkConfiguration(); + + int handleCacheConfiguration(); + + // + // These must be called just after initialization to + // tell to the proxy where the network connections + // have to be forwarded. + // + + virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, + sockaddr * xServerAddr, unsigned int xServerAddrLength) = 0; + + virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort) = 0; + + // + // Create new tunneled channels. + // + + virtual int handleNewConnection(T_channel_type type, int clientFd) = 0; + + virtual int handleNewConnectionFromProxy(T_channel_type type, int channelId) = 0; + + virtual int handleNewAgentConnection(Agent *agent) = 0; + + virtual int handleNewXConnection(int clientFd) = 0; + + virtual int handleNewXConnectionFromProxy(int channelId) = 0; + + int handleNewGenericConnection(int clientFd, T_channel_type type, const char *label); + + int handleNewGenericConnectionFromProxy(int channelId, T_channel_type type, + ChannelEndPoint &endpoint, const char *label); + + int handleNewGenericConnectionFromProxyUnix(int channelId, T_channel_type type, + const char *path, const char *label); + + int handleNewGenericConnectionFromProxyTCP(int channelId, T_channel_type type, + const char *hostname, long port, const char *label); + + int handleNewSlaveConnection(int clientFd); + + int handleNewSlaveConnectionFromProxy(int channelId); + + void checkSlaves(); + + // + // Force closure of channels. + // + + int handleCloseConnection(int clientFd); + + int handleCloseAllXConnections(); + + int handleCloseAllListeners(); + + // + // Called when the loop has replaced + // or closed a previous alert. + // + + void handleResetAlert(); + + // + // Handle the persistent cache. + // + + virtual int handleLoad(T_load_type type) = 0; + + virtual int handleSave() = 0; + + protected: + + // + // Timeout related data: + // + // flush + // split + // motion + // + // Timeouts in milliseconds after which the + // proxy will have to perform the operation. + // + // readTs, writeTs + // + // Timestamp of last packet received or sent + // to remote proxy. Used to detect lost con- + // nection. + // + // loopTs + // + // Timestamp of last loop completed by the + // proxy + // + // pingTs + // + // Timestamp of last ping request sent to the + // remote peer. + // + // alertTs + // + // Timestamp of last 'no data received' alert + // dialog shown to the user. + // + // loadTs + // + // Were message stores populated from data on + // disk. + // + // splitTs + // motionTs + // + // Timestamps of the last operation of this + // kind handled by the proxy. + // + + typedef struct + { + int split; + int motion; + + T_timestamp readTs; + T_timestamp writeTs; + + T_timestamp loopTs; + T_timestamp pingTs; + T_timestamp alertTs; + T_timestamp loadTs; + + T_timestamp splitTs; + T_timestamp motionTs; + + } T_proxy_timeouts; + + // + // Bytes accumulated so far while waiting + // to send the next token, number of tokens + // remaining for each token type and other + // token related information. + // + + typedef struct + { + int size; + int limit; + + int bytes; + int remaining; + + T_proxy_code request; + T_proxy_code reply; + + T_token_type type; + + } T_proxy_token; + + int handlePostConnectionFromProxy(int channelId, int serverFd, + T_channel_type type, const char *label); + + int handleDrain(); + + int handleFrame(T_frame_type type); + + int handleFinish(int channelId); + + int handleDrop(int channelId); + + int handleFinishFromProxy(int channelId); + + int handleDropFromProxy(int channelId); + + int handleStatisticsFromProxy(int type); + + int handleStatisticsFromProxy(const unsigned char *message, unsigned int length); + + int handleNegotiation(const unsigned char *message, unsigned int length); + + int handleNegotiationFromProxy(const unsigned char *message, unsigned int length); + + int handleToken(T_frame_type type); + + int handleTokenFromProxy(T_proxy_token &token, int count); + + int handleTokenReplyFromProxy(T_proxy_token &token, int count); + + int handleSyncFromProxy(int channelId); + + int handleSwitch(int channelId); + + int handleControl(T_proxy_code code, int data = -1); + + int handleControlFromProxy(const unsigned char *message); + + // + // Interleave reads of the X server + // events while writing data to the + // remote proxy. + // + + virtual int handleAsyncEvents() = 0; + + // + // Timer related functions. + // + + protected: + + void setTimer(int value) + { + SetTimer(value); + } + + void resetTimer() + { + ResetTimer(); + + timer_ = 0; + } + + public: + + void handleTimer() + { + timer_ = 1; + } + + int getTimer() + { + return timer_; + } + + // + // Can the channel consume data and the + // proxy produce more output? + // + + int canRead(int fd) const + { + return (isTimeToRead() == 1 && + isTimeToRead(getChannel(fd)) == 1); + } + + // + // Can the proxy read more data from its + // peer? + // + + int canRead() const + { + return (transport_ -> readable() != 0); + } + + int canFlush() const + { + return (encodeBuffer_.getLength() + + controlLength_ + transport_ -> length() + + transport_ -> flushable() > 0); + } + + int needFlush(int channelId) const + { + return (outputChannel_ == channelId && + encodeBuffer_.getLength() > 0); + } + + int needFlush() const + { + return (encodeBuffer_.getLength() > 0); + } + + int shouldFlush() const + { + if ((int) ((encodeBuffer_.getLength() + + controlLength_) / statistics -> + getStreamRatio()) >= control -> TokenSize) + { + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "Proxy: FLUSH! Requesting a flush with " + << (encodeBuffer_.getLength() + controlLength_) + << " bytes and stream ratio " << (double) statistics -> + getStreamRatio() << ".\n" << logofs_flush; + #endif + + return 1; + } + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "Proxy: Not requesting a flush with " + << (encodeBuffer_.getLength() + controlLength_) + << " bytes and stream ratio " << (double) statistics -> + getStreamRatio() << ".\n" << logofs_flush; + #endif + + return 0; + } + + int needDrain() const + { + return (congestion_ == 1 || transport_ -> length() > + control -> TransportProxyBufferThreshold); + } + + int getFd() const + { + return fd_; + } + + int getFlushable(int fd) const + { + if (fd == fd_) + { + return (encodeBuffer_.getLength() + controlLength_ + + transport_ -> flushable()); + } + + return 0; + } + + int getSplitSize() + { + return (clientStore_ != NULL ? clientStore_ -> + getSplitTotalSize() : 0); + } + + int getSplitStorageSize() + { + return (clientStore_ != NULL ? clientStore_ -> + getSplitTotalStorageSize() : 0); + } + + // + // Returns the number of active channels + // that currently managed by this proxy. + // + + int getChannels(T_channel_type type = channel_none); + + // + // If descriptor corresponds to a valid + // channel, returns the type of traffic + // carried by it. + // + + T_channel_type getType(int fd); + + // + // Given a channel type, returns the + // literal name. + // + + const char *getTypeName(T_channel_type type); + + // + // Get a convenient name for 'localhost'. + // + + const char *getComputerName(); + + // + // Set if we have initiated the shutdown + // procedure and if the shutdown request + // has been received from the remote. + // + + int getFinish() const + { + return finish_; + } + + int getShutdown() const + { + return shutdown_; + } + + // + // Interfaces to the transport buffers. + // + + int getLength(int fd) const + { + if (fd == fd_) + { + return transport_ -> length(); + } + + int channelId = getChannel(fd); + + if (channelId < 0 || channels_[channelId] == NULL) + { + return 0; + } + + return transports_[channelId] -> length(); + } + + int getPending(int fd) const + { + if (fd == fd_) + { + return transport_ -> pending(); + } + + int channelId = getChannel(fd); + + if (channelId < 0 || channels_[channelId] == NULL) + { + return 0; + } + + return transports_[channelId] -> pending(); + } + + // + // Check if the proxy or the given channel + // has data in the buffer because of a + // blocking write. + // + + int getBlocked(int fd) const + { + if (fd == fd_) + { + return transport_ -> blocked(); + } + + int channelId = getChannel(fd); + + if (channelId < 0 || channels_[channelId] == NULL) + { + return 0; + } + + return transports_[channelId] -> blocked(); + } + + // + // Check if the proxy or the given channel has + // data to read. + // + + int getReadable(int fd) const + { + if (fd == fd_) + { + return transport_ -> readable(); + } + + int channelId = getChannel(fd); + + if (channelId < 0 || channels_[channelId] == NULL) + { + return 0; + } + + return transports_[channelId] -> readable(); + } + + // + // Return a vale between 0 and 9 in the case + // of the proxy descriptor. + // + + int getCongestion(int fd) const + { + if (fd == fd_) + { + return (agent_ != nothing && congestions_[agent_] == 1 ? 9 : + (int) statistics -> getCongestionInFrame()); + } + + int channelId = getChannel(fd); + + if (channelId < 0 || channels_[channelId] == NULL) + { + return 0; + } + + return channels_[channelId] -> getCongestion(); + } + + // + // Let the statistics class get info + // from the message stores. + // + + const ClientStore * const getClientStore() const + { + return clientStore_; + } + + const ServerStore * const getServerStore() const + { + return serverStore_; + } + + // + // These can be called asynchronously by + // channels during their read or write + // loop. + // + + int handleAsyncRead(int fd) + { + return handleRead(fd); + } + + int handleAsyncCongestion(int fd) + { + int channelId = getChannel(fd); + + return handleControl(code_begin_congestion, channelId); + } + + int handleAsyncDecongestion(int fd) + { + int channelId = getChannel(fd); + + return handleControl(code_end_congestion, channelId); + } + + int handleAsyncSplit(int fd, Split *split) + { + return channels_[getChannel(fd)] -> + handleSplitEvent(encodeBuffer_, split); + } + + int handleAsyncPriority() + { + if (control -> FlushPriority == 1) + { + return handleFlush(); + } + + return 0; + } + + int canAsyncFlush() const + { + return shouldFlush(); + } + + int handleAsyncFlush() + { + return handleFlush(); + } + + int handleAsyncSwitch(int fd) + { + return handleSwitch(getChannel(fd)); + } + + int handleAsyncKeeperCallback() + { + KeeperCallback(); + + return 1; + } + + // + // Internal interfaces used to verify the + // availability of channels and the proxy + // link. + // + + protected: + + int isTimeToRead() const + { + if (congestion_ == 0 && transport_ -> + blocked() == 0) + { + return 1; + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Can't read from channels " + << "with congestion " << congestion_ + << " and blocked " << transport_ -> + blocked() << ".\n" << logofs_flush; + #endif + + return 0; + } + } + + int isTimeToRead(int channelId) const + { + if (channelId >= 0 && channelId < CONNECTIONS_LIMIT && + channels_[channelId] != NULL && + congestions_[channelId] == 0) + { + if (channels_[channelId] -> getType() == channel_x11 || + tokens_[token_data].remaining > 0 || + channels_[channelId] -> + getFinish() == 1) + { + return 1; + } + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: Can't read from generic " + << "descriptor FD#" << getFd(channelId) + << " channel ID#" << channelId << " with " + << tokens_[token_data].remaining + << " data tokens remaining.\n" + << logofs_flush; + #endif + + return 0; + } + + #if defined(TEST) || defined(INFO) + + if (channelId < 0 || channelId >= CONNECTIONS_LIMIT || + channels_[channelId] == NULL) + { + *logofs << "Proxy: WARNING! No valid channel for ID#" + << channelId << ".\n" << logofs_flush; + } + else if (channels_[channelId] -> getFinish()) + { + *logofs << "Proxy: Can't read from finishing " + << "descriptor FD#" << getFd(channelId) + << " channel ID#" << channelId << ".\n" + << logofs_flush; + } + else if (congestions_[channelId] == 1) + { + *logofs << "Proxy: Can't read from congested " + << "descriptor FD#" << getFd(channelId) + << " channel ID#" << channelId << ".\n" + << logofs_flush; + } + + #endif + + return 0; + } + + // + // Handle the flush and split timeouts. + // All these functions should round up + // to the value of the latency timeout + // to save a further loop. + // + + protected: + + int isTimeToSplit() const + { + if (isTimestamp(timeouts_.splitTs) && + getTimeToNextSplit() <= control -> + LatencyTimeout) + { + if (tokens_[token_split].remaining > 0) + { + return 1; + } + + #if defined(TEST) || defined(INFO) + *logofs << "Proxy: WARNING! Can't encode splits " + << "with " << tokens_[token_split].remaining + << " split tokens remaining.\n" + << logofs_flush; + #endif + } + + return 0; + } + + int isTimeToMotion() const + { + return (isTimestamp(timeouts_.motionTs) && + getTimeToNextMotion() <= control -> + LatencyTimeout); + } + + int getTimeToNextSplit() const + { + #if defined(TEST) || defined(INFO) || defined(FLUSH) + + if (isTimestamp(timeouts_.splitTs) == 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! No split timeout was set " + << "for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": No split timeout was set " + << "for proxy FD#" << fd_ << ".\n"; + + HandleCleanup(); + } + + #endif + + int diffTs = timeouts_.split - + diffTimestamp(timeouts_.splitTs, + getTimestamp()); + + return (diffTs > 0 ? diffTs : 0); + } + + int getTimeToNextMotion() const + { + #if defined(TEST) || defined(INFO) || defined(FLUSH) + + if (isTimestamp(timeouts_.motionTs) == 0) + { + #ifdef PANIC + *logofs << "Proxy: PANIC! No motion timeout was set " + << "for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": No motion timeout was set " + << "for proxy FD#" << fd_ << ".\n"; + + HandleCleanup(); + } + + #endif + + int diffTs = timeouts_.motion - + diffTimestamp(timeouts_.motionTs, + getTimestamp()); + + return (diffTs > 0 ? diffTs : 0); + } + + protected: + + // + // Implement persistence of cache on disk. + // + + virtual int handleLoadFromProxy() = 0; + virtual int handleSaveFromProxy() = 0; + + int handleLoadStores(); + int handleSaveStores(); + + char *handleSaveAllStores(const char *savePath, bool & isTooSmall) const; + + virtual int handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient) const = 0; + + int handleSaveVersion(unsigned char *buffer, int &major, int &minor, int &patch) const; + + void handleFailOnSave(const char *fullName, const char *failContext) const; + + const char *handleLoadAllStores(const char *loadPath, const char *loadName) const; + + virtual int handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const = 0; + + int handleLoadVersion(const unsigned char *buffer, int &major, int &minor, int &patch) const; + + void handleFailOnLoad(const char *fullName, const char *failContext) const; + + // + // Prepare for a new persistent cache. + // + + int handleResetPersistentCache(); + + // + // Reset the stores in the case of a + // failure loading the cache. + // + + int handleResetStores(); + + // + // Reset the transport buffer and the + // other counters. + // + + void handleResetFlush(); + + // + // Utility functions used to map file + // descriptors to channel ids. + // + + protected: + + int allocateChannelMap(int fd); + int checkChannelMap(int channelId); + int assignChannelMap(int channelId, int fd); + + void cleanupChannelMap(int channelId); + + virtual int checkLocalChannelMap(int channelId) = 0; + + int addControlCodes(T_proxy_code code, int data); + int addTokenCodes(T_proxy_token &token); + + int getFd(int channelId) const + { + if (channelId >= 0 && channelId < CONNECTIONS_LIMIT) + { + return fdMap_[channelId]; + } + + return -1; + } + + int getChannel(int fd) const + { + if (fd >= 0 && fd < CONNECTIONS_LIMIT) + { + return channelMap_[fd]; + } + + return -1; + } + + protected: + + void setSplitTimeout(int channelId); + void setMotionTimeout(int channelId); + + void increaseChannels(int channelId); + void decreaseChannels(int channelId); + + int allocateTransport(int channelFd, int channelId); + int deallocateTransport(int channelId); + + // + // The proxy has its own transport. + // + + ProxyTransport *transport_; + + // + // The static compressor is shared among + // channels and all the message stores. + // + + StaticCompressor *compressor_; + + // + // Map NX specific opcodes. + // + + OpcodeStore *opcodeStore_; + + // + // Stores are shared between channels. + // + + ClientStore *clientStore_; + ServerStore *serverStore_; + + // + // Client and server caches are shared + // between channels. + // + + ClientCache *clientCache_; + ServerCache *serverCache_; + + // + // The proxy's file descriptor. + // + + int fd_; + + // + // Channels currently selected for I/O + // operations. + // + + int inputChannel_; + int outputChannel_; + + // + // List of active channels. + // + + List activeChannels_; + + // + // Used to read data sent from peer proxy. + // + + ProxyReadBuffer readBuffer_; + + // + // Used to send data to peer proxy. + // + + EncodeBuffer encodeBuffer_; + + // + // Control messages' array. + // + + int controlLength_; + + unsigned char controlCodes_[CONTROL_CODES_LENGTH]; + + // + // Table of channel classes taking + // care of open X connections. + // + + Channel *channels_[CONNECTIONS_LIMIT]; + + // + // Table of open sockets. + // + + Transport *transports_[CONNECTIONS_LIMIT]; + + // + // Timeout related data. + // + + T_proxy_timeouts timeouts_; + + // + // Proxy can be decoding messages, + // handling a link reconfiguration, + // or decoding statistics. + // + + int operation_; + + // + // True if we are currently draining + // the proxy link. + // + + int draining_; + + // + // Force flush because of prioritized + // control messages to send. + // + + int priority_; + + // + // Set if we have initiated the close + // down procedure. + // + + int finish_; + + // + // Remote peer requested the shutdown. + // + + int shutdown_; + + // + // We are in the middle of a network + // congestion in the path to remote + // proxy. + // + + int congestion_; + + // + // Channels at the remote end that + // are not consuming their data. + // + + int congestions_[CONNECTIONS_LIMIT]; + + // + // Is the timer expired? + // + + int timer_; + + // + // Did the proxy request an alert? + // + + int alert_; + + // + // The channel id of the agent. + // + + int agent_; + + // + // Token related data. + // + + T_proxy_token tokens_[TOKEN_TYPES]; + + // + // Pointer to stream descriptor where + // proxy is producing statistics. + // + + ostream *currentStatistics_; + + private: + + // + // Map channel ids to file descriptors. + // + + int channelMap_[CONNECTIONS_LIMIT]; + int fdMap_[CONNECTIONS_LIMIT]; + int slavePidMap_[CONNECTIONS_LIMIT]; +}; + +#endif /* Proxy_H */ diff --git a/nxcomp/src/ProxyReadBuffer.cpp b/nxcomp/src/ProxyReadBuffer.cpp new file mode 100644 index 000000000..77f12771b --- /dev/null +++ b/nxcomp/src/ProxyReadBuffer.cpp @@ -0,0 +1,211 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ProxyReadBuffer.h" + +#include "Transport.h" + +// +// Set the verbosity level. You also +// need to define DUMP in Misc.cpp +// if DUMP is defined here. +// + +#define WARNING +#define PANIC +#undef TEST +#undef DEBUG +#undef DUMP + +unsigned int ProxyReadBuffer::suggestedLength(unsigned int pendingLength) +{ + // + // Always read all the data that + // is available. + // + + int readable = transport_ -> readable(); + + unsigned int readLength = (readable == -1 ? 0 : (unsigned int) readable); + + if (readLength < pendingLength) + { + readLength = pendingLength; + } + + // + // Even if the readable data is not + // enough to make a complete message, + // resize the buffer to accommodate + // it all. + // + + if (pendingLength < remaining_) + { + readLength = remaining_; + } + + return readLength; +} + +int ProxyReadBuffer::locateMessage(const unsigned char *start, + const unsigned char *end, + unsigned int &controlLength, + unsigned int &dataLength, + unsigned int &trailerLength) +{ + unsigned int lengthLength = 0; + const unsigned char *nextSrc = start; + unsigned char next; + + dataLength = 0; + + #ifdef TEST + *logofs << "ProxyReadBuffer: Locating message for FD#" + << transport_ -> fd() << " with " << end - start + << " bytes.\n" << logofs_flush; + #endif + + // + // Use something like the following if + // you are looking for errors. + // + + #ifdef DUMP + if (control -> ProxyMode == proxy_server && start < end && + transport_ -> fd() == 6 || transport_ -> fd() == 11) + { + *logofs << "ProxyReadBuffer: Partial checksums are:\n"; + + DumpBlockChecksums(start, end - start, 256); + + *logofs << logofs_flush; + } + #endif + + do + { + if (nextSrc >= end) + { + remaining_ = 1; + + #ifdef TEST + *logofs << "ProxyReadBuffer: No message was located " + << "with remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + + next = *nextSrc++; + + dataLength <<= 7; + dataLength |= (unsigned int) (next & 0x7f); + + lengthLength++; + } + while (next & 0x80); + + unsigned int totalLength; + + if (dataLength == 0) + { + trailerLength = 0; + controlLength = 3; + totalLength = controlLength; + } + else + { + trailerLength = lengthLength; + controlLength = 0; + totalLength = dataLength + trailerLength; + } + + if (start + totalLength > end) + { + // + // When having to decompress a ZLIB stream, + // a single byte can be enough to complete + // the frame. + // + + if (control -> RemoteStreamCompression == 0) + { + remaining_ = totalLength - (end - start); + } + else + { + remaining_ = 1; + } + + #ifdef TEST + *logofs << "ProxyReadBuffer: No message was located " + << "with remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + else + { + #ifdef DUMP + *logofs << "ProxyReadBuffer: Received " << totalLength << " bytes of data " + << "with checksum "; + + DumpChecksum(start, totalLength); + + *logofs << " on proxy FD#" << transport_ -> fd() << ".\n" << logofs_flush; + #endif + + #if defined(TEST) || defined(INFO) + *logofs << "ProxyReadBuffer: Produced plain input for " << dataLength + << "+" << trailerLength << "+" << controlLength << " bytes out of " + << totalLength << " bytes.\n" << logofs_flush; + #endif + + #ifdef DUMP + *logofs << "ProxyReadBuffer: Partial checksums are:\n"; + + DumpBlockChecksums(start, totalLength, 256); + + *logofs << logofs_flush; + #endif + + remaining_ = 0; + + #ifdef TEST + *logofs << "ProxyReadBuffer: Located message with " + << "remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 1; + } +} diff --git a/nxcomp/src/ProxyReadBuffer.h b/nxcomp/src/ProxyReadBuffer.h new file mode 100644 index 000000000..68e9e95fa --- /dev/null +++ b/nxcomp/src/ProxyReadBuffer.h @@ -0,0 +1,57 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ProxyReadBuffer_H +#define ProxyReadBuffer_H + +#include "ReadBuffer.h" +#include "Control.h" + +class ProxyReadBuffer : public ReadBuffer +{ + public: + + ProxyReadBuffer(Transport *transport) + + : ReadBuffer(transport) + { + } + + virtual ~ProxyReadBuffer() + { + } + + protected: + + virtual unsigned int suggestedLength(unsigned int pendingLength); + + virtual int locateMessage(const unsigned char *start, + const unsigned char *end, + unsigned int &controlLength, + unsigned int &dataLength, + unsigned int &trailerLength); +}; + +#endif /* ProxyReadBuffer_H */ diff --git a/nxcomp/src/PutImage.cpp b/nxcomp/src/PutImage.cpp new file mode 100644 index 000000000..d14f922c3 --- /dev/null +++ b/nxcomp/src/PutImage.cpp @@ -0,0 +1,411 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PutImage.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +PutImageStore::PutImageStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = PUTIMAGE_ENABLE_CACHE; + enableData = PUTIMAGE_ENABLE_DATA; + + // Since ProtoStep7 (#issue 108) + enableCompress = PUTIMAGE_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = PUTIMAGE_DATA_LIMIT; + dataOffset = PUTIMAGE_DATA_OFFSET; + + cacheSlots = PUTIMAGE_CACHE_SLOTS; + cacheThreshold = PUTIMAGE_CACHE_THRESHOLD; + cacheLowerThreshold = PUTIMAGE_CACHE_LOWER_THRESHOLD; + + // Since ProtoStep8 (#issue 108) + enableSplit = PUTIMAGE_ENABLE_SPLIT_IF_PROTO_STEP_8; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +PutImageStore::~PutImageStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int PutImageStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; + #endif + + encodeBuffer.encodeValue(GetUINT(buffer + 2, bigEndian), 16, 8); + + encodeBuffer.encodeValue((unsigned int) buffer[1], 2); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> drawableCache); + encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), + clientCache -> gcCache); + + unsigned int width = GetUINT(buffer + 12, bigEndian); + encodeBuffer.encodeCachedValue(width, 16, + clientCache -> putImageWidthCache, 8); + + unsigned int height = GetUINT(buffer + 14, bigEndian); + encodeBuffer.encodeCachedValue(height, 16, + clientCache -> putImageHeightCache, 8); + + unsigned int x = GetUINT(buffer + 16, bigEndian); + int xDiff = x - clientCache -> putImageLastX; + clientCache -> putImageLastX = x; + encodeBuffer.encodeCachedValue(xDiff, 16, + clientCache -> putImageXCache, 8); + + unsigned int y = GetUINT(buffer + 18, bigEndian); + int yDiff = y - clientCache -> putImageLastY; + clientCache -> putImageLastY = y; + encodeBuffer.encodeCachedValue(yDiff, 16, + clientCache -> putImageYCache, 8); + + encodeBuffer.encodeCachedValue(buffer[20], 8, + clientCache -> putImageLeftPadCache); + + encodeBuffer.encodeCachedValue(buffer[21], 8, + clientCache -> depthCache); + + #ifdef DEBUG + *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int PutImageStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; + #endif + + unsigned int value; + unsigned char cValue; + + decodeBuffer.decodeValue(value, 16, 8); + + size = (value << 2); + + buffer = writeBuffer -> addMessage(size); + + decodeBuffer.decodeValue(value, 2); + buffer[1] = (unsigned char) value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + PutULONG(value, buffer + 4, bigEndian); + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + PutULONG(value, buffer + 8, bigEndian); + + unsigned int width; + decodeBuffer.decodeCachedValue(width, 16, + clientCache -> putImageWidthCache, 8); + PutUINT(width, buffer + 12, bigEndian); + + unsigned int height; + decodeBuffer.decodeCachedValue(height, 16, + clientCache -> putImageHeightCache, 8); + PutUINT(height, buffer + 14, bigEndian); + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageXCache, 8); + clientCache -> putImageLastX += value; + clientCache -> putImageLastX &= 0xffff; + PutUINT(clientCache -> putImageLastX, buffer + 16, bigEndian); + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageYCache, 8); + clientCache -> putImageLastY += value; + clientCache -> putImageLastY &= 0xffff; + PutUINT(clientCache -> putImageLastY, buffer + 18, bigEndian); + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> putImageLeftPadCache); + buffer[20] = cValue; + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + buffer[21] = cValue; + + #ifdef DEBUG + *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int PutImageStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PutImageMessage *putImage = (PutImageMessage *) message; + + // + // Here is the fingerprint. + // + + putImage -> format = *(buffer + 1); + putImage -> depth = *(buffer + 21); + putImage -> left_pad = *(buffer + 20); + + putImage -> width = GetUINT(buffer + 12, bigEndian); + putImage -> height = GetUINT(buffer + 14, bigEndian); + putImage -> pos_x = GetUINT(buffer + 16, bigEndian); + putImage -> pos_y = GetUINT(buffer + 18, bigEndian); + + putImage -> drawable = GetULONG(buffer + 4, bigEndian); + putImage -> gcontext = GetULONG(buffer + 8, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PutImageStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PutImageMessage *putImage = (PutImageMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = putImage -> format; + + PutULONG(putImage -> drawable, buffer + 4, bigEndian); + PutULONG(putImage -> gcontext, buffer + 8, bigEndian); + + PutUINT(putImage -> width, buffer + 12, bigEndian); + PutUINT(putImage -> height, buffer + 14, bigEndian); + PutUINT(putImage -> pos_x, buffer + 16, bigEndian); + PutUINT(putImage -> pos_y, buffer + 18, bigEndian); + + *(buffer + 20) = (unsigned char) putImage -> left_pad; + *(buffer + 21) = (unsigned char) putImage -> depth; + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PutImageStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PutImageMessage *putImage = (PutImageMessage *) message; + + *logofs << name() << ": Identity format " << (unsigned) putImage -> format + << ", depth " << (unsigned) putImage -> depth << ", left_pad " + << (unsigned) putImage -> left_pad << ", width " << putImage -> width + << ", height " << putImage -> height << ", pos_x " << putImage -> pos_x + << ", pos_y " << putImage -> pos_y << ", drawable " << putImage -> drawable + << ", gcontext " << putImage -> gcontext << ", size " << putImage -> size_ + << ".\n" << logofs_flush; + + #endif +} + +void PutImageStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Fields format, width, height, left_pad, depth. + // + + md5_append(md5_state_, buffer + 1, 1); + md5_append(md5_state_, buffer + 12, 4); + md5_append(md5_state_, buffer + 20, 2); +} + +void PutImageStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + // + // Encode the variant part. + // + + PutImageMessage *putImage = (PutImageMessage *) message; + PutImageMessage *cachedPutImage = (PutImageMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putImage -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(putImage -> drawable, clientCache -> drawableCache); + + cachedPutImage -> drawable = putImage -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putImage -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(putImage -> gcontext, clientCache -> gcCache); + + cachedPutImage -> gcontext = putImage -> gcontext; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putImage -> pos_x + << " as " << "pos_x" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_x = putImage -> pos_x - cachedPutImage -> pos_x; + + encodeBuffer.encodeCachedValue(diff_x, 16, + clientCache -> putImageXCache, 8); + + cachedPutImage -> pos_x = putImage -> pos_x; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putImage -> pos_y + << " as " << "pos_y" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_y = putImage -> pos_y - cachedPutImage -> pos_y; + + encodeBuffer.encodeCachedValue(diff_y, 16, + clientCache -> putImageYCache, 8); + + cachedPutImage -> pos_y = putImage -> pos_y; +} + +void PutImageStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + // + // Decode the variant part. + // + + PutImageMessage *putImage = (PutImageMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + putImage -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putImage -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + putImage -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putImage -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageXCache, 8); + + putImage -> pos_x += value; + putImage -> pos_x &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putImage -> pos_x + << " as pos_x field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageYCache, 8); + + putImage -> pos_y += value; + putImage -> pos_y &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putImage -> pos_y + << " as pos_y field.\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/PutImage.h b/nxcomp/src/PutImage.h new file mode 100644 index 000000000..93dde9dfb --- /dev/null +++ b/nxcomp/src/PutImage.h @@ -0,0 +1,172 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PutImage_H +#define PutImage_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define PUTIMAGE_ENABLE_CACHE 1 +#define PUTIMAGE_ENABLE_DATA 1 + +#define PUTIMAGE_DATA_LIMIT 262144 - 24 +#define PUTIMAGE_DATA_OFFSET 24 + +#define PUTIMAGE_CACHE_SLOTS 6000 +#define PUTIMAGE_CACHE_THRESHOLD 70 +#define PUTIMAGE_CACHE_LOWER_THRESHOLD 50 + +#define PUTIMAGE_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +#define PUTIMAGE_CACHE_THRESHOLD_IF_PACKED 10 +#define PUTIMAGE_CACHE_LOWER_THRESHOLD_IF_PACKED 5 + +#define PUTIMAGE_CACHE_THRESHOLD_IF_SHADOW 97 +#define PUTIMAGE_CACHE_LOWER_THRESHOLD_IF_SHADOW 90 + +#define PUTIMAGE_ENABLE_SPLIT_IF_PROTO_STEP_8 0 + +// +// The message class. +// + +class PutImageMessage : public Message +{ + friend class PutImageStore; + + public: + + PutImageMessage() + { + } + + ~PutImageMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char format; + unsigned char depth; + unsigned char left_pad; + unsigned short width; + unsigned short height; + unsigned int drawable; + unsigned int gcontext; + unsigned short pos_x; + unsigned short pos_y; +}; + +class PutImageStore : public MessageStore +{ + public: + + PutImageStore(StaticCompressor *compressor); + + virtual ~PutImageStore(); + + virtual const char *name() const + { + return "PutImage"; + } + + virtual unsigned char opcode() const + { + return X_PutImage; + } + + virtual unsigned int storage() const + { + return sizeof(PutImageMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new PutImageMessage(); + } + + virtual Message *create(const Message &message) const + { + return new PutImageMessage((const PutImageMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (PutImageMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PutImage_H */ diff --git a/nxcomp/src/PutPackedImage.cpp b/nxcomp/src/PutPackedImage.cpp new file mode 100644 index 000000000..0bae2c0d4 --- /dev/null +++ b/nxcomp/src/PutPackedImage.cpp @@ -0,0 +1,604 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "PutPackedImage.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +PutPackedImageStore::PutPackedImageStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = PUTPACKEDIMAGE_ENABLE_CACHE; + enableData = PUTPACKEDIMAGE_ENABLE_DATA; + enableCompress = PUTPACKEDIMAGE_ENABLE_COMPRESS; + + dataLimit = PUTPACKEDIMAGE_DATA_LIMIT; + dataOffset = PUTPACKEDIMAGE_DATA_OFFSET; + + cacheSlots = PUTPACKEDIMAGE_CACHE_SLOTS; + cacheThreshold = PUTPACKEDIMAGE_CACHE_THRESHOLD; + cacheLowerThreshold = PUTPACKEDIMAGE_CACHE_LOWER_THRESHOLD; + + // Since ProtoStep8 (#issue 108) + enableSplit = PUTPACKEDIMAGE_ENABLE_SPLIT_IF_PROTO_STEP_8; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +PutPackedImageStore::~PutPackedImageStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int PutPackedImageStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; + #endif + + // Client. + encodeBuffer.encodeCachedValue(*(buffer + 1), 8, + clientCache -> resourceCache); + + // Size. + encodeBuffer.encodeValue(GetUINT(buffer + 2, bigEndian), 16, 10); + + // Drawable. + encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> drawableCache); + // GC. + encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), + clientCache -> gcCache); + // Method. + encodeBuffer.encodeCachedValue(*(buffer + 12), 8, + clientCache -> methodCache); + // Format. + encodeBuffer.encodeValue(*(buffer + 13), 2); + + // SrcDepth. + encodeBuffer.encodeCachedValue(*(buffer + 14), 8, + clientCache -> depthCache); + // DstDepth. + encodeBuffer.encodeCachedValue(*(buffer + 15), 8, + clientCache -> depthCache); + // SrcLength. + encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 24, + clientCache -> putPackedImageSrcLengthCache); + // DstLength. + encodeBuffer.encodeCachedValue(GetULONG(buffer + 20, bigEndian), 24, + clientCache -> putPackedImageDstLengthCache); + // SrcX. + unsigned int x = GetUINT(buffer + 24, bigEndian); + int xDiff = x - clientCache -> putImageLastX; + clientCache -> putImageLastX = x; + encodeBuffer.encodeCachedValue(xDiff, 16, + clientCache -> putImageXCache, 8); + // SrcY. + unsigned int y = GetUINT(buffer + 26, bigEndian); + int yDiff = y - clientCache -> putImageLastY; + clientCache -> putImageLastY = y; + encodeBuffer.encodeCachedValue(yDiff, 16, + clientCache -> putImageYCache, 8); + // SrcWidth. + encodeBuffer.encodeCachedValue(GetUINT(buffer + 28, bigEndian), 16, + clientCache -> putImageWidthCache, 8); + // SrcHeight. + encodeBuffer.encodeCachedValue(GetUINT(buffer + 30, bigEndian), 16, + clientCache -> putImageHeightCache, 8); + // DstX. + x = GetUINT(buffer + 32, bigEndian); + xDiff = x - clientCache -> putImageLastX; + clientCache -> putImageLastX = x; + encodeBuffer.encodeCachedValue(xDiff, 16, + clientCache -> putImageXCache, 8); + // DstY. + y = GetUINT(buffer + 34, bigEndian); + yDiff = y - clientCache -> putImageLastY; + clientCache -> putImageLastY = y; + encodeBuffer.encodeCachedValue(yDiff, 16, + clientCache -> putImageYCache, 8); + // DstWidth. + encodeBuffer.encodeCachedValue(GetUINT(buffer + 36, bigEndian), 16, + clientCache -> putImageWidthCache, 8); + // DstHeight. + encodeBuffer.encodeCachedValue(GetUINT(buffer + 38, bigEndian), 16, + clientCache -> putImageHeightCache, 8); + + #ifdef DEBUG + *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int PutPackedImageStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; + #endif + + unsigned int value; + unsigned char cValue; + + // Client. + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> resourceCache); + + // Size. + decodeBuffer.decodeValue(size, 16, 10); + + size <<= 2; + + buffer = writeBuffer -> addMessage(size); + + *(buffer + 1) = cValue; + + // Drawable. + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + PutULONG(value, buffer + 4, bigEndian); + + // GC. + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + PutULONG(value, buffer + 8, bigEndian); + + // Method. + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> methodCache); + *(buffer + 12) = cValue; + + // Format. + decodeBuffer.decodeValue(value, 2); + *(buffer + 13) = value; + + // SrcDepth. + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + *(buffer + 14) = cValue; + + // DstDepth. + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + *(buffer + 15) = cValue; + + // SrcLength. + decodeBuffer.decodeCachedValue(value, 24, + clientCache -> putPackedImageSrcLengthCache); + PutULONG(value, buffer + 16, bigEndian); + + // DstLength. + decodeBuffer.decodeCachedValue(value, 24, + clientCache -> putPackedImageDstLengthCache); + PutULONG(value, buffer + 20, bigEndian); + + // SrcX. + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageXCache, 8); + clientCache -> putImageLastX += value; + clientCache -> putImageLastX &= 0xffff; + PutUINT(clientCache -> putImageLastX, buffer + 24, bigEndian); + + // SrcY. + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageYCache, 8); + clientCache -> putImageLastY += value; + clientCache -> putImageLastY &= 0xffff; + PutUINT(clientCache -> putImageLastY, buffer + 26, bigEndian); + + // SrcWidth. + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageWidthCache, 8); + PutUINT(value, buffer + 28, bigEndian); + + // SrcHeight. + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageHeightCache, 8); + PutUINT(value, buffer + 30, bigEndian); + + // DstX. + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageXCache, 8); + clientCache -> putImageLastX += value; + clientCache -> putImageLastX &= 0xffff; + PutUINT(clientCache -> putImageLastX, buffer + 32, bigEndian); + + // DstY. + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageYCache, 8); + clientCache -> putImageLastY += value; + clientCache -> putImageLastY &= 0xffff; + PutUINT(clientCache -> putImageLastY, buffer + 34, bigEndian); + + // DstWidth. + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageWidthCache, 8); + PutUINT(value, buffer + 36, bigEndian); + + // DstHeight. + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageHeightCache, 8); + PutUINT(value, buffer + 38, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int PutPackedImageStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; + + // + // Here is the fingerprint. + // + + putPackedImage -> client = *(buffer + 1); + + putPackedImage -> drawable = GetULONG(buffer + 4, bigEndian); + putPackedImage -> gcontext = GetULONG(buffer + 8, bigEndian); + + putPackedImage -> method = *(buffer + 12); + + putPackedImage -> format = *(buffer + 13); + putPackedImage -> src_depth = *(buffer + 14); + putPackedImage -> dst_depth = *(buffer + 15); + + putPackedImage -> src_length = GetULONG(buffer + 16, bigEndian); + putPackedImage -> dst_length = GetULONG(buffer + 20, bigEndian); + + putPackedImage -> src_x = GetUINT(buffer + 24, bigEndian); + putPackedImage -> src_y = GetUINT(buffer + 26, bigEndian); + putPackedImage -> src_width = GetUINT(buffer + 28, bigEndian); + putPackedImage -> src_height = GetUINT(buffer + 30, bigEndian); + + putPackedImage -> dst_x = GetUINT(buffer + 32, bigEndian); + putPackedImage -> dst_y = GetUINT(buffer + 34, bigEndian); + putPackedImage -> dst_width = GetUINT(buffer + 36, bigEndian); + putPackedImage -> dst_height = GetUINT(buffer + 38, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int PutPackedImageStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = putPackedImage -> client; + + PutULONG(putPackedImage -> drawable, buffer + 4, bigEndian); + PutULONG(putPackedImage -> gcontext, buffer + 8, bigEndian); + + *(buffer + 12) = putPackedImage -> method; + + *(buffer + 13) = putPackedImage -> format; + *(buffer + 14) = putPackedImage -> src_depth; + *(buffer + 15) = putPackedImage -> dst_depth; + + PutULONG(putPackedImage -> src_length, buffer + 16, bigEndian); + PutULONG(putPackedImage -> dst_length, buffer + 20, bigEndian); + + PutUINT(putPackedImage -> src_x, buffer + 24, bigEndian); + PutUINT(putPackedImage -> src_y, buffer + 26, bigEndian); + PutUINT(putPackedImage -> src_width, buffer + 28, bigEndian); + PutUINT(putPackedImage -> src_height, buffer + 30, bigEndian); + + PutUINT(putPackedImage -> dst_x, buffer + 32, bigEndian); + PutUINT(putPackedImage -> dst_y, buffer + 34, bigEndian); + PutUINT(putPackedImage -> dst_width, buffer + 36, bigEndian); + PutUINT(putPackedImage -> dst_height, buffer + 38, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void PutPackedImageStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; + + *logofs << name() << ": Identity format " + + << "drawable " << putPackedImage -> drawable << ", " + << "gcontext " << putPackedImage -> gcontext << ", " + + << "format " << (unsigned int) putPackedImage -> format << ", " + << "method " << (unsigned int) putPackedImage -> method << ", " + + << "src_depth " << (unsigned int) putPackedImage -> src_depth << ", " + << "dst_depth " << (unsigned int) putPackedImage -> dst_depth << ", " + + << "src_length " << putPackedImage -> src_length << ", " + << "dst_length " << putPackedImage -> dst_length << ", " + + << "src_x " << putPackedImage -> src_x << ", " + << "src_y " << putPackedImage -> src_y << ", " + << "src_width " << putPackedImage -> src_width << ", " + << "src_height " << putPackedImage -> src_height << ", " + + << "dst_x " << putPackedImage -> dst_x << ", " + << "dst_y " << putPackedImage -> dst_y << ", " + << "dst_width " << putPackedImage -> dst_width << ", " + << "dst_height " << putPackedImage -> dst_height << ", " + + << "size " << putPackedImage -> size_ << ".\n" + << logofs_flush; + + #endif +} + +void PutPackedImageStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Fields method, format, src_depth, dst_depth, + // src_length, dst_length, src_x, src_y, src_width, + // src_height. + // + // + // TODO: We should better investigate the effect of + // having fields src_x and src_y in identity instead + // of keeping them in differences. + // + + md5_append(md5_state_, buffer + 12, 20); +} + +void PutPackedImageStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + // + // Encode the variant part. + // + + PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; + PutPackedImageMessage *cachedPutPackedImage = (PutPackedImageMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " + << (unsigned int) putPackedImage -> client + << " as client field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(putPackedImage -> client, 8, + clientCache -> resourceCache); + + cachedPutPackedImage -> client = putPackedImage -> client; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putPackedImage -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(putPackedImage -> drawable, clientCache -> drawableCache); + + cachedPutPackedImage -> drawable = putPackedImage -> drawable; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putPackedImage -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(putPackedImage -> gcontext, clientCache -> gcCache); + + cachedPutPackedImage -> gcontext = putPackedImage -> gcontext; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putPackedImage -> dst_x + << " as " << "dst_x" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_x = putPackedImage -> dst_x - cachedPutPackedImage -> dst_x; + + encodeBuffer.encodeCachedValue(diff_x, 16, + clientCache -> putImageXCache, 8); + + cachedPutPackedImage -> dst_x = putPackedImage -> dst_x; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putPackedImage -> dst_y + << " as " << "dst_y" << " field.\n" << logofs_flush; + #endif + + unsigned short int diff_y = putPackedImage -> dst_y - cachedPutPackedImage -> dst_y; + + encodeBuffer.encodeCachedValue(diff_y, 16, + clientCache -> putImageYCache, 8); + + cachedPutPackedImage -> dst_y = putPackedImage -> dst_y; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putPackedImage -> dst_width + << " as " << "dst_width" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(putPackedImage -> dst_width, 16, + clientCache -> putImageWidthCache, 8); + + cachedPutPackedImage -> dst_width = putPackedImage -> dst_width; + + #ifdef TEST + *logofs << name() << ": Encoding value " << putPackedImage -> dst_height + << " as " << "dst_height" << " field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(putPackedImage -> dst_height, 16, + clientCache -> putImageHeightCache, 8); + + cachedPutPackedImage -> dst_height = putPackedImage -> dst_height; +} + +void PutPackedImageStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + // + // Decode the variant part. + // + + PutPackedImageMessage *putPackedImage = (PutPackedImageMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeCachedValue(putPackedImage -> client, 8, + clientCache -> resourceCache); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " + << (unsigned int) putPackedImage -> client + << " as client field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> drawableCache); + + putPackedImage -> drawable = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putPackedImage -> drawable + << " as drawable field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + putPackedImage -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putPackedImage -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageXCache, 8); + + putPackedImage -> dst_x += value; + putPackedImage -> dst_x &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putPackedImage -> dst_x + << " as dst_x field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageYCache, 8); + + putPackedImage -> dst_y += value; + putPackedImage -> dst_y &= 0xffff; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putPackedImage -> dst_y + << " as dst_y field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageWidthCache, 8); + + putPackedImage -> dst_width = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putPackedImage -> dst_width + << " as dst_width field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> putImageHeightCache, 8); + + putPackedImage -> dst_height = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << putPackedImage -> dst_height + << " as dst_height field.\n" << logofs_flush; + #endif +} + diff --git a/nxcomp/src/PutPackedImage.h b/nxcomp/src/PutPackedImage.h new file mode 100644 index 000000000..d28ad39eb --- /dev/null +++ b/nxcomp/src/PutPackedImage.h @@ -0,0 +1,218 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef PutPackedImage_H +#define PutPackedImage_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define PUTPACKEDIMAGE_ENABLE_CACHE 1 +#define PUTPACKEDIMAGE_ENABLE_DATA 1 +#define PUTPACKEDIMAGE_ENABLE_COMPRESS 0 + +// +// We can't exceed lenght of 262144 bytes. +// + +#define PUTPACKEDIMAGE_DATA_LIMIT 262144 - 40 +#define PUTPACKEDIMAGE_DATA_OFFSET 40 + +#define PUTPACKEDIMAGE_CACHE_SLOTS 6000 +#define PUTPACKEDIMAGE_CACHE_THRESHOLD 70 +#define PUTPACKEDIMAGE_CACHE_LOWER_THRESHOLD 50 + +#define PUTPACKEDIMAGE_CACHE_THRESHOLD_IF_PACKED_SHADOW 97 +#define PUTPACKEDIMAGE_CACHE_LOWER_THRESHOLD_IF_PACKED_SHADOW 90 + +#define PUTPACKEDIMAGE_ENABLE_SPLIT_IF_PROTO_STEP_8 0 + +// +// The message class. +// + +class PutPackedImageMessage : public Message +{ + friend class PutPackedImageStore; + + public: + + PutPackedImageMessage() + { + } + + ~PutPackedImageMessage() + { + } + + // + // Here are the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char client; + + unsigned int drawable; + unsigned int gcontext; + + unsigned char format; + unsigned char method; + + unsigned char src_depth; + unsigned char dst_depth; + + unsigned int src_length; + unsigned int dst_length; + + short int src_x; + short int src_y; + unsigned short src_width; + unsigned short src_height; + + short int dst_x; + short int dst_y; + unsigned short dst_width; + unsigned short dst_height; +}; + +class PutPackedImageStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + PutPackedImageStore(StaticCompressor *compressor); + + virtual ~PutPackedImageStore(); + + virtual const char *name() const + { + return "PutPackedImage"; + } + + virtual unsigned char opcode() const + { + return X_NXPutPackedImage; + } + + virtual unsigned int storage() const + { + return sizeof(PutPackedImageMessage); + } + + // + // Very special of this class. + // + + int getPackedSize(const int position) const + { + PutPackedImageMessage *message = (PutPackedImageMessage *) (*messages_)[position]; + + if (message == NULL) + { + return 0; + } + + return dataOffset + message -> src_length; + } + + int getUnpackedSize(const int position) const + { + PutPackedImageMessage *message = (PutPackedImageMessage *) (*messages_)[position]; + + if (message == NULL) + { + return 0; + } + + return dataOffset + message -> dst_length; + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new PutPackedImageMessage(); + } + + virtual Message *create(const Message &message) const + { + return new PutPackedImageMessage((const PutPackedImageMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (PutPackedImageMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* PutPackedImage_H */ diff --git a/nxcomp/src/QueryFontReply.cpp b/nxcomp/src/QueryFontReply.cpp new file mode 100644 index 000000000..fde873140 --- /dev/null +++ b/nxcomp/src/QueryFontReply.cpp @@ -0,0 +1,154 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "QueryFontReply.h" + +#include "ServerCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +QueryFontReplyStore::QueryFontReplyStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = QUERYFONTREPLY_ENABLE_CACHE; + enableData = QUERYFONTREPLY_ENABLE_DATA; + enableSplit = QUERYFONTREPLY_ENABLE_SPLIT; + + // Since ProtoStep7 (#issue 108) + enableCompress = QUERYFONTREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = QUERYFONTREPLY_DATA_LIMIT; + dataOffset = QUERYFONTREPLY_DATA_OFFSET; + + cacheSlots = QUERYFONTREPLY_CACHE_SLOTS; + cacheThreshold = QUERYFONTREPLY_CACHE_THRESHOLD; + cacheLowerThreshold = QUERYFONTREPLY_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +QueryFontReplyStore::~QueryFontReplyStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int QueryFontReplyStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Clear the padding bytes. + // + + unsigned char *pad = (unsigned char *) buffer; + + if (size >= 24) + { + PutULONG(0, pad + 20, bigEndian); + } + + if (size >= 40) + { + PutULONG(0, pad + 36, bigEndian); + } + + // + // TODO: This doesn't work. Probably these + // padding bytes are not padding anymore. + // This is to be investigated. + // + // pad += 60; + // + // while (pad + 16 <= (buffer + size)) + // { + // PutULONG(0, pad + 12, bigEndian); + // + // pad += 16; + // } + // + + #ifdef DEBUG + *logofs << name() << ": Cleaned padding bytes of " + << "message at " << message << ".\n" + << logofs_flush; + #endif + + return 1; +} + +int QueryFontReplyStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + return 1; +} + +void QueryFontReplyStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + QueryFontReplyMessage *queryFontReply = (QueryFontReplyMessage *) message; + + *logofs << name() << ": Identity size " << queryFontReply -> size_ << ".\n"; + + #endif +} + +void QueryFontReplyStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +} diff --git a/nxcomp/src/QueryFontReply.h b/nxcomp/src/QueryFontReply.h new file mode 100644 index 000000000..e12fe4e4b --- /dev/null +++ b/nxcomp/src/QueryFontReply.h @@ -0,0 +1,136 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef QueryFontReply_H +#define QueryFontReply_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// +#define QUERYFONTREPLY_ENABLE_CACHE 1 +#define QUERYFONTREPLY_ENABLE_DATA 1 +#define QUERYFONTREPLY_ENABLE_SPLIT 0 + +#define QUERYFONTREPLY_DATA_LIMIT 1048576 - 32 +#define QUERYFONTREPLY_DATA_OFFSET 8 + +#define QUERYFONTREPLY_CACHE_SLOTS 200 +#define QUERYFONTREPLY_CACHE_THRESHOLD 20 +#define QUERYFONTREPLY_CACHE_LOWER_THRESHOLD 5 + +#define QUERYFONTREPLY_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +// +// The message class. +// + +class QueryFontReplyMessage : public Message +{ + friend class QueryFontReplyStore; + + public: + + QueryFontReplyMessage() + { + } + + ~QueryFontReplyMessage() + { + } +}; + +class QueryFontReplyStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + QueryFontReplyStore(StaticCompressor *compressor); + + virtual ~QueryFontReplyStore(); + + virtual const char *name() const + { + return "QueryFontReply"; + } + + virtual unsigned char opcode() const + { + return X_QueryFont; + } + + virtual unsigned int storage() const + { + return sizeof(QueryFontReplyMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new QueryFontReplyMessage(); + } + + virtual Message *create(const Message &message) const + { + return new QueryFontReplyMessage((const QueryFontReplyMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (QueryFontReplyMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* QueryFontReply_H */ diff --git a/nxcomp/src/ReadBuffer.cpp b/nxcomp/src/ReadBuffer.cpp new file mode 100644 index 000000000..154225e75 --- /dev/null +++ b/nxcomp/src/ReadBuffer.cpp @@ -0,0 +1,639 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ReadBuffer.h" + +#include "Transport.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +ReadBuffer::ReadBuffer(Transport *transport) + + : transport_(transport) +{ + // + // The read buffer will grow until + // reaching the maximum buffer size + // and then will remain stable at + // that size. + // + + initialReadSize_ = READ_BUFFER_DEFAULT_SIZE; + maximumBufferSize_ = READ_BUFFER_DEFAULT_SIZE; + + size_ = 0; + buffer_ = NULL; + + owner_ = 1; + length_ = 0; + start_ = 0; + + remaining_ = 0; +} + +ReadBuffer::~ReadBuffer() +{ + if (owner_ == 1) + { + delete [] buffer_; + } +} + +void ReadBuffer::readMessage(const unsigned char *message, unsigned int length) +{ + // + // To be here we must be the real owner + // of the buffer and there must not be + // pending bytes in the transport. + // + + #ifdef TEST + + if (owner_ == 0) + { + *logofs << "ReadBuffer: PANIC! Class for FD#" + << transport_ -> fd() << " doesn't " + << "appear to be the owner of the buffer " + << "while borrowing from the caller.\n" + << logofs_flush; + + HandleCleanup(); + } + + #endif + + // + // Be sure that any outstanding data from + // the transport is appended to our own + // byffer. + // + + if (transport_ -> pending() != 0) + { + #ifdef WARNING + *logofs << "ReadBuffer: WARNING! Class for FD#" + << transport_ -> fd() << " has pending " + << "data in the transport while " + << "borrowing from the caller.\n" + << logofs_flush; + #endif + + readMessage(); + + if (owner_ == 0) + { + convertBuffer(); + } + } + + // + // Can't borrow the buffer if there is data + // from a partial message. In this case add + // the new data to the end of our buffer. + // + + if (length_ == 0) + { + #ifdef TEST + *logofs << "ReadBuffer: Borrowing " << length + << " bytes from the caller for FD#" + << transport_ -> fd() << " with " + << length_ << " bytes in the buffer.\n" + << logofs_flush; + #endif + + delete [] buffer_; + + buffer_ = (unsigned char *) message; + size_ = length; + + length_ = length; + + owner_ = 0; + start_ = 0; + } + else + { + #ifdef TEST + *logofs << "ReadBuffer: Appending " << length + << " bytes from the caller for FD#" + << transport_ -> fd() << " with " + << length_ << " bytes in the buffer.\n" + << logofs_flush; + #endif + + appendBuffer(message, length); + } +} + +int ReadBuffer::readMessage() +{ + int pendingLength = transport_ -> pending(); + + if (pendingLength > 0) + { + // + // Can't move the data in the borrowed buffer, + // so use the tansport buffer only if we don't + // have any partial message. This can happen + // with the proxy where we need to deflate the + // stream. + // + + if (length_ == 0) + { + unsigned char *newBuffer; + + length_ = transport_ -> getPending(newBuffer); + + if (newBuffer == NULL) + { + #ifdef PANIC + *logofs << "ReadBuffer: PANIC! Failed to borrow " + << length_ << " bytes of memory for buffer " + << "in context [A].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to borrow memory for " + << "read buffer in context [A].\n"; + + HandleCleanup(); + } + + delete [] buffer_; + + buffer_ = newBuffer; + size_ = length_; + + owner_ = 0; + start_ = 0; + + #ifdef TEST + *logofs << "ReadBuffer: Borrowed " << length_ + << " pending bytes for FD#" << transport_ -> + fd() << ".\n" << logofs_flush; + #endif + + return length_; + } + #ifdef TEST + else + { + *logofs << "ReadBuffer: WARNING! Cannot borrow " + << pendingLength << " bytes for FD#" + << transport_ -> fd() << " with " + << length_ << " bytes in the buffer.\n" + << logofs_flush; + } + #endif + } + + unsigned int readLength = suggestedLength(pendingLength); + + #ifdef DEBUG + *logofs << "ReadBuffer: Requested " << readLength + << " bytes for FD#" << transport_ -> fd() + << " with readable " << transport_ -> readable() + << " remaining " << remaining_ << " pending " + << transport_ -> pending() << ".\n" + << logofs_flush; + #endif + + if (readLength < initialReadSize_) + { + readLength = initialReadSize_; + } + + #ifdef DEBUG + *logofs << "ReadBuffer: Buffer size is " << size_ + << " length " << length_ << " and start " + << start_ << ".\n" << logofs_flush; + #endif + + // + // We can't use the transport buffer + // to read our own data in it. + // + + #ifdef TEST + + if (owner_ == 0) + { + *logofs << "ReadBuffer: PANIC! Class for FD#" + << transport_ -> fd() << " doesn't " + << "appear to be the owner of the buffer " + << "while reading.\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + // + // Be sure that we have enough space + // to store all the requested data. + // + + if (buffer_ == NULL || length_ + readLength > size_) + { + unsigned int newSize = length_ + readLength; + + #ifdef TEST + *logofs << "ReadBuffer: Resizing buffer for FD#" + << transport_ -> fd() << " in read from " + << size_ << " to " << newSize << " bytes.\n" + << logofs_flush; + #endif + + unsigned char *newBuffer = allocateBuffer(newSize); + + memcpy(newBuffer, buffer_ + start_, length_); + + delete [] buffer_; + + buffer_ = newBuffer; + size_ = newSize; + + transport_ -> pendingReset(); + + owner_ = 1; + } + else if (start_ != 0 && length_ != 0) + { + // + // If any bytes are left due to a partial + // message, shift them to the beginning + // of the buffer. + // + + #ifdef TEST + *logofs << "ReadBuffer: Moving " << length_ + << " bytes of data " << "at beginning of " + << "the buffer for FD#" << transport_ -> fd() + << ".\n" << logofs_flush; + #endif + + memmove(buffer_, buffer_ + start_, length_); + } + + start_ = 0; + + #ifdef DEBUG + *logofs << "ReadBuffer: Buffer size is now " << size_ + << " length is " << length_ << " and start is " + << start_ << ".\n" << logofs_flush; + #endif + + unsigned char *readData = buffer_ + length_; + + #ifdef DEBUG + *logofs << "ReadBuffer: Going to read " << readLength + << " bytes from FD#" << transport_ -> fd() << ".\n" + << logofs_flush; + #endif + + int bytesRead = transport_ -> read(readData, readLength); + + if (bytesRead > 0) + { + #ifdef TEST + *logofs << "ReadBuffer: Read " << bytesRead + << " bytes from FD#" << transport_ -> fd() + << ".\n" << logofs_flush; + #endif + + length_ += bytesRead; + } + else if (bytesRead < 0) + { + // + // Check if there is more data pending than the + // size of the provided buffer. After reading + // the requested amount, in fact, the transport + // may have decompressed the data and produced + // more input. This trick allows us to always + // borrow the buffer from the transport, even + // when the partial read would have prevented + // that. + // + + if (transport_ -> pending() > 0) + { + #ifdef TEST + *logofs << "ReadBuffer: WARNING! Trying to read some " + << "more with " << transport_ -> pending() + << " bytes pending for FD#" << transport_ -> + fd() << ".\n" << logofs_flush; + #endif + + return readMessage(); + } + + #ifdef TEST + *logofs << "ReadBuffer: Error detected reading " + << "from FD#" << transport_ -> fd() + << ".\n" << logofs_flush; + #endif + + return -1; + } + #ifdef TEST + else + { + *logofs << "ReadBuffer: No data read from FD#" + << transport_ -> fd() << " with remaining " + << remaining_ << ".\n" << logofs_flush; + } + #endif + + return bytesRead; +} + +const unsigned char *ReadBuffer::getMessage(unsigned int &controlLength, + unsigned int &dataLength) +{ + #ifdef TEST + + if (transport_ -> pending() > 0) + { + *logofs << "ReadBuffer: PANIC! The transport " + << "appears to have data pending.\n" + << logofs_flush; + + HandleCleanup(); + } + + #endif + + if (length_ == 0) + { + #ifdef DEBUG + *logofs << "ReadBuffer: No message can be located " + << "for FD#" << transport_ -> fd() << ".\n" + << logofs_flush; + #endif + + if (owner_ == 0) + { + buffer_ = NULL; + size_ = 0; + + transport_ -> pendingReset(); + + owner_ = 1; + start_ = 0; + } + + return NULL; + } + + unsigned int trailerLength; + + #ifdef DEBUG + *logofs << "ReadBuffer: Going to locate message with " + << "start at " << start_ << " and length " + << length_ << " for FD#" << transport_ -> fd() + << ".\n" << logofs_flush; + #endif + + int located = locateMessage(buffer_ + start_, buffer_ + start_ + length_, + controlLength, dataLength, trailerLength); + + if (located == 0) + { + // + // No more complete messages are in + // the buffer. + // + + #ifdef DEBUG + *logofs << "ReadBuffer: No message was located " + << "for FD#" << transport_ -> fd() + << ".\n" << logofs_flush; + #endif + + if (owner_ == 0) + { + // + // Must move the remaining bytes in + // our own buffer. + // + + convertBuffer(); + } + + return NULL; + } + else + { + const unsigned char *result = buffer_ + start_; + + if (dataLength > 0) + { + // + // Message contains data, so go to the + // first byte of payload. + // + + result += trailerLength; + + start_ += (dataLength + trailerLength); + length_ -= (dataLength + trailerLength); + } + else + { + // + // It is a control message. + // + + start_ += (controlLength + trailerLength); + length_ -= (controlLength + trailerLength); + } + + #ifdef DEBUG + *logofs << "ReadBuffer: Located message for FD#" + << transport_ -> fd() << " with control length " + << controlLength << " and data length " + << dataLength << ".\n" << logofs_flush; + #endif + + remaining_ = 0; + + return result; + } +} + +int ReadBuffer::setSize(int initialReadSize, int maximumBufferSize) +{ + initialReadSize_ = initialReadSize; + maximumBufferSize_ = maximumBufferSize; + + #ifdef TEST + *logofs << "ReadBuffer: WARNING! Set buffer parameters to " + << initialReadSize_ << "/" << maximumBufferSize_ + << " for object at "<< this << ".\n" + << logofs_flush; + #endif + + return 1; +} + +void ReadBuffer::fullReset() +{ + #ifdef TEST + + if (owner_ == 0) + { + *logofs << "ReadBuffer: PANIC! Class for FD#" + << transport_ -> fd() << " doesn't " + << "appear to be the owner of the buffer " + << "in reset.\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + if (length_ == 0 && size_ > maximumBufferSize_) + { + #ifdef TEST + *logofs << "ReadBuffer: Resizing buffer for FD#" + << transport_ -> fd() << " in reset from " + << size_ << " to " << maximumBufferSize_ + << " bytes.\n" << logofs_flush; + #endif + + delete [] buffer_; + + int newSize = maximumBufferSize_; + + unsigned char *newBuffer = allocateBuffer(newSize); + + buffer_ = newBuffer; + size_ = newSize; + + transport_ -> pendingReset(); + + owner_ = 1; + start_ = 0; + } +} + +unsigned char *ReadBuffer::allocateBuffer(unsigned int newSize) +{ + unsigned char *newBuffer = new unsigned char[newSize]; + + if (newBuffer == NULL) + { + #ifdef PANIC + *logofs << "ReadBuffer: PANIC! Can't allocate " + << newSize << " bytes of memory for buffer " + << "in context [B].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory for " + << "read buffer in context [B].\n"; + + HandleCleanup(); + } + + #ifdef VALGRIND + + memset(newBuffer, '\0', newSize); + + #endif + + return newBuffer; +} + +void ReadBuffer::appendBuffer(const unsigned char *message, unsigned int length) +{ + if (start_ + length_ + length > size_) + { + unsigned int newSize = length_ + length + initialReadSize_; + + #ifdef TEST + *logofs << "ReadBuffer: WARNING! Resizing buffer " + << "for FD#" << transport_ -> fd() + << " from " << size_ << " to " << newSize + << " bytes.\n" << logofs_flush; + #endif + + unsigned char *newBuffer = allocateBuffer(newSize); + + memcpy(newBuffer, buffer_ + start_, length_); + + delete [] buffer_; + + buffer_ = newBuffer; + size_ = newSize; + + start_ = 0; + } + + memcpy(buffer_ + start_ + length_, message, length); + + length_ += length; + + transport_ -> pendingReset(); + + owner_ = 1; +} + +void ReadBuffer::convertBuffer() +{ + unsigned int newSize = length_ + initialReadSize_; + + #ifdef TEST + *logofs << "ReadBuffer: WARNING! Converting " + << length_ << " bytes to own buffer " + << "for FD#" << transport_ -> fd() + << " with new size " << newSize + << " bytes.\n" << logofs_flush; + #endif + + unsigned char *newBuffer = allocateBuffer(newSize); + + memcpy(newBuffer, buffer_ + start_, length_); + + buffer_ = newBuffer; + size_ = newSize; + + transport_ -> pendingReset(); + + owner_ = 1; + start_ = 0; +} diff --git a/nxcomp/src/ReadBuffer.h b/nxcomp/src/ReadBuffer.h new file mode 100644 index 000000000..a12bcc9b3 --- /dev/null +++ b/nxcomp/src/ReadBuffer.h @@ -0,0 +1,128 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ReadBuffer_H +#define ReadBuffer_H + +#include "Misc.h" +#include "Timestamp.h" +#include "Transport.h" + +#define READ_BUFFER_DEFAULT_SIZE 8192 + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +class ReadBuffer +{ + public: + + ReadBuffer(Transport *transport); + + virtual ~ReadBuffer(); + + int readMessage(); + + void readMessage(const unsigned char *message, unsigned int length); + + const unsigned char *getMessage(unsigned int &dataLength) + { + unsigned int controlLength; + + return getMessage(controlLength, dataLength); + } + + const unsigned char *getMessage(unsigned int &controlLength, unsigned int &dataLength); + + unsigned int getLength() const + { + return length_; + } + + unsigned int getRemaining() const + { + return remaining_; + } + + int setSize(int initialReadSize, int initialbufferSize); + + void fullReset(); + + // + // Check if there is a complete + // message in the buffer. + // + + int checkMessage() + { + if (length_ == 0) + { + return 0; + } + else + { + unsigned int controlLength; + unsigned int dataLength; + unsigned int trailerLength; + + return (locateMessage(buffer_ + start_, buffer_ + start_ + length_, + controlLength, dataLength, trailerLength)); + } + } + + protected: + + virtual unsigned int suggestedLength(unsigned int pendingLength) = 0; + + virtual int locateMessage(const unsigned char *start, + const unsigned char *end, + unsigned int &controlLength, + unsigned int &dataLength, + unsigned int &trailerLength) = 0; + + unsigned char *allocateBuffer(unsigned int newSize); + + void appendBuffer(const unsigned char *message, unsigned int length); + + void convertBuffer(); + + Transport *transport_; + + unsigned char *buffer_; + + unsigned int length_; + unsigned int size_; + unsigned int start_; + unsigned int remaining_; + + int owner_; + + unsigned int initialReadSize_; + unsigned int maximumBufferSize_; +}; + +#endif /* ReadBuffer_H */ diff --git a/nxcomp/src/RenderAddGlyphs.cpp b/nxcomp/src/RenderAddGlyphs.cpp new file mode 100644 index 000000000..ef13d6890 --- /dev/null +++ b/nxcomp/src/RenderAddGlyphs.cpp @@ -0,0 +1,233 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +// +// Include the template for +// this message class. +// + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "RenderAddGlyphs.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + size = MESSAGE_OFFSET + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 4, bigEndian), 29, + clientCache -> renderGlyphSetCache); + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 8, bigEndian), 32, + clientCache -> renderNumGlyphsCache, 8); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeCachedValue(value, 29, + clientCache -> renderGlyphSetCache); + + PutULONG(value, buffer + 4, bigEndian); + + decodeBuffer.decodeCachedValue(value, 32, + clientCache -> renderNumGlyphsCache, 8); + + PutULONG(value, buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.add_glyphs.type = *(buffer + 1); + + renderExtension -> data.add_glyphs.set_id = GetULONG(buffer + 4, bigEndian); + renderExtension -> data.add_glyphs.num_elm = GetULONG(buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.add_glyphs.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.add_glyphs.type; + + PutULONG(renderExtension -> data.add_glyphs.set_id, buffer + 4, bigEndian); + PutULONG(renderExtension -> data.add_glyphs.num_elm, buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.add_glyphs.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + md5_append(md5_state, buffer + 1, 3); + md5_append(md5_state, buffer + 8, 4); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(renderExtension -> data.add_glyphs.set_id, 29, + clientCache -> renderGlyphSetCache); + + cachedRenderExtension -> data.add_glyphs.set_id = + renderExtension -> data.add_glyphs.set_id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.add_glyphs.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(renderExtension -> data.add_glyphs.set_id, 29, + clientCache -> renderGlyphSetCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.add_glyphs.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderAddGlyphs.h b/nxcomp/src/RenderAddGlyphs.h new file mode 100644 index 000000000..d3c8cd158 --- /dev/null +++ b/nxcomp/src/RenderAddGlyphs.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderAddGlyphs_H +#define RenderAddGlyphs_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderAddGlyphs" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderAddGlyphsStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 12 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderAddGlyphs_H */ diff --git a/nxcomp/src/RenderChangePicture.cpp b/nxcomp/src/RenderChangePicture.cpp new file mode 100644 index 000000000..d202b92ad --- /dev/null +++ b/nxcomp/src/RenderChangePicture.cpp @@ -0,0 +1,238 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +// +// Include the template for +// this message class. +// + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "RenderChangePicture.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + size = MESSAGE_OFFSET + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> renderSrcPictureCache); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeXidValue(value, clientCache -> renderSrcPictureCache); + + PutULONG(value, buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + #ifdef DEBUG + + if (size == MESSAGE_OFFSET + 4) + { + *logofs << name() << ": Mask is " << GetULONG(buffer + 8, bigEndian) + << " value is " << GetULONG(buffer + 12, bigEndian) + << ".\n" << logofs_flush; + } + else + { + *logofs << name() << ": WARNING! Unexpected size. Mask is " + << GetULONG(buffer + 8, bigEndian) << ".\n" + << logofs_flush; + } + + #endif + + encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.change_picture.type = *(buffer + 1); + + renderExtension -> data.change_picture.src_id = GetULONG(buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.change_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.change_picture.type; + + PutULONG(renderExtension -> data.change_picture.src_id, buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.change_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + md5_append(md5_state, buffer + 1, 3); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(renderExtension -> data.change_picture.src_id, + clientCache -> renderSrcPictureCache); + + cachedRenderExtension -> data.change_picture.src_id = + renderExtension -> data.change_picture.src_id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.change_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(renderExtension -> data.change_picture.src_id, + clientCache -> renderSrcPictureCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.change_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderChangePicture.h b/nxcomp/src/RenderChangePicture.h new file mode 100644 index 000000000..4bab1ef98 --- /dev/null +++ b/nxcomp/src/RenderChangePicture.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderChangePicture_H +#define RenderChangePicture_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderChangePicture" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderChangePictureStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 8 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderChangePicture_H */ diff --git a/nxcomp/src/RenderComposite.cpp b/nxcomp/src/RenderComposite.cpp new file mode 100644 index 000000000..f82f80f06 --- /dev/null +++ b/nxcomp/src/RenderComposite.cpp @@ -0,0 +1,400 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +// +// Include the template for +// this message class. +// + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "RenderComposite.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), + clientCache -> renderSrcPictureCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 12, bigEndian), + clientCache -> renderMaskPictureCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 16, bigEndian), + clientCache -> renderDstPictureCache); + + // + // Src X and Y. + // + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 20, bigEndian), + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 22, bigEndian), + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + // + // Mask X and Y. + // + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 24, bigEndian), + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 26, bigEndian), + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + // + // Dst X and Y. + // + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 28, bigEndian), + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 30, bigEndian), + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + // + // Width and height. + // + + encodeBuffer.encodeCachedValue(GetUINT(buffer + 32, bigEndian), 16, + clientCache -> renderWidthCache, 11); + + encodeBuffer.encodeCachedValue(GetUINT(buffer + 34, bigEndian), 16, + clientCache -> renderHeightCache, 11); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + decodeBuffer.decodeXidValue(value, clientCache -> renderSrcPictureCache); + + PutULONG(value, buffer + 8, bigEndian); + + decodeBuffer.decodeXidValue(value, clientCache -> renderMaskPictureCache); + + PutULONG(value, buffer + 12, bigEndian); + + decodeBuffer.decodeXidValue(value, clientCache -> renderDstPictureCache); + + PutULONG(value, buffer + 16, bigEndian); + + // + // Src X and Y. + // + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + PutUINT(clientCache -> renderLastX, buffer + 20, bigEndian); + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + PutUINT(clientCache -> renderLastY, buffer + 22, bigEndian); + + // + // Mask X and Y. + // + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + PutUINT(clientCache -> renderLastX, buffer + 24, bigEndian); + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + PutUINT(clientCache -> renderLastY, buffer + 26, bigEndian); + + // + // Dst X and Y. + // + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + PutUINT(clientCache -> renderLastX, buffer + 28, bigEndian); + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + PutUINT(clientCache -> renderLastY, buffer + 30, bigEndian); + + // + // Width and height. + // + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> renderWidthCache, 11); + + PutUINT(value, buffer + 32, bigEndian); + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> renderHeightCache, 11); + + PutUINT(value, buffer + 34, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.composite.type = *(buffer + 1); + renderExtension -> data.composite.op = *(buffer + 4); + + renderExtension -> data.composite.src_id = GetULONG(buffer + 8, bigEndian); + renderExtension -> data.composite.msk_id = GetULONG(buffer + 12, bigEndian); + renderExtension -> data.composite.dst_id = GetULONG(buffer + 16, bigEndian); + + renderExtension -> data.composite.src_x = GetUINT(buffer + 20, bigEndian); + renderExtension -> data.composite.src_y = GetUINT(buffer + 22, bigEndian); + + renderExtension -> data.composite.msk_x = GetUINT(buffer + 24, bigEndian); + renderExtension -> data.composite.msk_y = GetUINT(buffer + 26, bigEndian); + + renderExtension -> data.composite.dst_x = GetUINT(buffer + 28, bigEndian); + renderExtension -> data.composite.dst_y = GetUINT(buffer + 30, bigEndian); + + renderExtension -> data.composite.width = GetUINT(buffer + 32, bigEndian); + renderExtension -> data.composite.height = GetUINT(buffer + 34, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.composite.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.composite.type; + *(buffer + 4) = renderExtension -> data.composite.op; + + PutULONG(renderExtension -> data.composite.src_id, buffer + 8, bigEndian); + PutULONG(renderExtension -> data.composite.msk_id, buffer + 12, bigEndian); + PutULONG(renderExtension -> data.composite.dst_id, buffer + 16, bigEndian); + + PutUINT(renderExtension -> data.composite.src_x, buffer + 20, bigEndian); + PutUINT(renderExtension -> data.composite.src_y, buffer + 22, bigEndian); + + PutUINT(renderExtension -> data.composite.msk_x, buffer + 24, bigEndian); + PutUINT(renderExtension -> data.composite.msk_y, buffer + 26, bigEndian); + + PutUINT(renderExtension -> data.composite.dst_x, buffer + 28, bigEndian); + PutUINT(renderExtension -> data.composite.dst_y, buffer + 30, bigEndian); + + PutUINT(renderExtension -> data.composite.width, buffer + 32, bigEndian); + PutUINT(renderExtension -> data.composite.height, buffer + 34, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.composite.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + // + // Include the minor opcode and size in the + // identity, plus the operator, the x and y + // of the source and mask and the width and + // height of the destination. + // + + md5_append(md5_state, buffer + 1, 4); + md5_append(md5_state, buffer + 20, 8); + md5_append(md5_state, buffer + 32, 4); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Source " << renderExtension -> data.composite.src_id + << " mask " << renderExtension -> data.composite.msk_id + << " destination " << renderExtension -> data.composite.msk_id + << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(renderExtension -> data.composite.src_id, + clientCache -> renderSrcPictureCache); + + cachedRenderExtension -> data.composite.src_id = + renderExtension -> data.composite.src_id; + + encodeBuffer.encodeXidValue(renderExtension -> data.composite.msk_id, + clientCache -> renderMaskPictureCache); + + cachedRenderExtension -> data.composite.msk_id = + renderExtension -> data.composite.msk_id; + + encodeBuffer.encodeXidValue(renderExtension -> data.composite.dst_id, + clientCache -> renderDstPictureCache); + + cachedRenderExtension -> data.composite.dst_id = + renderExtension -> data.composite.dst_id; + + // + // Dst X and Y. + // + + unsigned int value; + unsigned int previous; + + value = renderExtension -> data.composite.dst_x; + previous = cachedRenderExtension -> data.composite.dst_x; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderXCache, 11); + + cachedRenderExtension -> data.composite.dst_x = value; + + value = renderExtension -> data.composite.dst_y; + previous = cachedRenderExtension -> data.composite.dst_y; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderYCache, 11); + + cachedRenderExtension -> data.composite.dst_y = value; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.composite.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(renderExtension -> data.composite.src_id, + clientCache -> renderSrcPictureCache); + + decodeBuffer.decodeXidValue(renderExtension -> data.composite.msk_id, + clientCache -> renderMaskPictureCache); + + decodeBuffer.decodeXidValue(renderExtension -> data.composite.dst_id, + clientCache -> renderDstPictureCache); + + // + // Dst X and Y. + // + + unsigned int value; + unsigned int previous; + + previous = renderExtension -> data.composite.dst_x; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderXCache, 11); + + renderExtension -> data.composite.dst_x = value; + + previous = renderExtension -> data.composite.dst_y; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderYCache, 11); + + renderExtension -> data.composite.dst_y = value; + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.composite.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderComposite.h b/nxcomp/src/RenderComposite.h new file mode 100644 index 000000000..aafa1e776 --- /dev/null +++ b/nxcomp/src/RenderComposite.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderComposite_H +#define RenderComposite_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderComposite" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderCompositeStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 36 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 0 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 0 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderComposite_H */ diff --git a/nxcomp/src/RenderCompositeGlyphs.cpp b/nxcomp/src/RenderCompositeGlyphs.cpp new file mode 100644 index 000000000..0949d3e2c --- /dev/null +++ b/nxcomp/src/RenderCompositeGlyphs.cpp @@ -0,0 +1,629 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderCompositeGlyphs.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding value " + << ((size - MESSAGE_OFFSET) >> 2) << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << size + << ".\n" << logofs_flush; + #endif + + size = MESSAGE_OFFSET + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), + clientCache -> renderSrcPictureCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 12, bigEndian), + clientCache -> renderDstPictureCache); + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 32, + clientCache -> renderFormatCache); + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 20, bigEndian), 29, + clientCache -> renderGlyphSetCache); + + unsigned int src_x = GetUINT(buffer + 24, bigEndian); + unsigned int src_y = GetUINT(buffer + 26, bigEndian); + + // Since ProtoStep8 (#issue 108) + encodeBuffer.encodeDiffCachedValue(src_x, + clientCache -> renderGlyphX, 16, + clientCache -> renderGlyphXCache, 11); + + encodeBuffer.encodeDiffCachedValue(src_y, + clientCache -> renderGlyphY, 16, + clientCache -> renderGlyphYCache, 11); + + #ifdef TEST + *logofs << name() << ": Encoded source X " + << GetUINT(buffer + 24, bigEndian) << " source Y " + << GetUINT(buffer + 26, bigEndian) << ".\n" + << logofs_flush; + #endif + + // + // Bytes from 28 to 36 contain in the order: + // + // 1 byte for the length of the first string. + // 3 bytes of padding. + // 2 bytes for the X offset. + // 2 bytes for the Y offset. + // + // Encode these bytes differentially to match + // all the strings that have equal glyphs. + // + // Only manage the first string of glyphs. The + // others strings should match, if they contain + // the same glyphs, since the offset are rela- + // tive to the first offset coordinates. + // + + // Since ProtoStep8 (#issue 108) + if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) + { + unsigned int numGlyphs = *(buffer + 28); + + encodeBuffer.encodeCachedValue(numGlyphs, 8, + clientCache -> renderNumGlyphsCache); + + unsigned int offset_x = GetUINT(buffer + 32, bigEndian); + unsigned int offset_y = GetUINT(buffer + 34, bigEndian); + + if (offset_x == src_x && offset_y == src_y) + { + encodeBuffer.encodeBoolValue(0); + + #ifdef TEST + *logofs << name() << ": Matched offset X " + << GetUINT(buffer + 32, bigEndian) << " offset Y " + << GetUINT(buffer + 34, bigEndian) << ".\n" + << logofs_flush; + #endif + } + else + { + encodeBuffer.encodeBoolValue(1); + + encodeBuffer.encodeDiffCachedValue(offset_x, + clientCache -> renderGlyphX, 16, + clientCache -> renderGlyphXCache, 11); + + encodeBuffer.encodeDiffCachedValue(offset_y, + clientCache -> renderGlyphY, 16, + clientCache -> renderGlyphYCache, 11); + + #ifdef TEST + *logofs << name() << ": Missed offset X " + << GetUINT(buffer + 32, bigEndian) << " offset Y " + << GetUINT(buffer + 34, bigEndian) << ".\n" + << logofs_flush; + #endif + } + } + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + decodeBuffer.decodeXidValue(value, + clientCache -> renderSrcPictureCache); + + PutULONG(value, buffer + 8, bigEndian); + + decodeBuffer.decodeXidValue(value, + clientCache -> renderDstPictureCache); + + PutULONG(value, buffer + 12, bigEndian); + + decodeBuffer.decodeCachedValue(value, 32, + clientCache -> renderFormatCache); + + PutULONG(value, buffer + 16, bigEndian); + + decodeBuffer.decodeCachedValue(value, 29, + clientCache -> renderGlyphSetCache); + + PutULONG(value, buffer + 20, bigEndian); + + unsigned int src_x; + unsigned int src_y; + + // Since ProtoStep8 (#issue 108) + decodeBuffer.decodeDiffCachedValue(src_x, + clientCache -> renderGlyphX, 16, + clientCache -> renderGlyphXCache, 11); + + decodeBuffer.decodeDiffCachedValue(src_y, + clientCache -> renderGlyphY, 16, + clientCache -> renderGlyphYCache, 11); + + PutUINT(src_x, buffer + 24, bigEndian); + PutUINT(src_y, buffer + 26, bigEndian); + + // Since ProtoStep8 (#issue 108) + if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) + { + decodeBuffer.decodeCachedValue(value, 8, + clientCache -> renderNumGlyphsCache); + + *(buffer + 28) = value; + + decodeBuffer.decodeBoolValue(value); + + if (value == 0) + { + PutUINT(src_x, buffer + 32, bigEndian); + PutUINT(src_y, buffer + 34, bigEndian); + } + else + { + decodeBuffer.decodeDiffCachedValue(src_x, + clientCache -> renderGlyphX, 16, + clientCache -> renderGlyphXCache, 11); + + PutUINT(src_x, buffer + 32, bigEndian); + + decodeBuffer.decodeDiffCachedValue(src_y, + clientCache -> renderGlyphY, 16, + clientCache -> renderGlyphYCache, 11); + + PutUINT(src_y, buffer + 34, bigEndian); + } + } + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + // Since ProtoStep8 (#issue 108) + if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) + { + encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET_IF_PROTO_STEP_8, + size, bigEndian, channelCache); + } + else if (size > MESSAGE_OFFSET) + { + encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + } + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of text data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + // Since ProtoStep8 (#issue 108) + if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) + { + decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET_IF_PROTO_STEP_8, + size, bigEndian, channelCache); + } + else if (size > MESSAGE_OFFSET) + { + decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + } + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.composite_glyphs.type = *(buffer + 1); + renderExtension -> data.composite_glyphs.op = *(buffer + 4); + + renderExtension -> data.composite_glyphs.src_id = GetULONG(buffer + 8, bigEndian); + renderExtension -> data.composite_glyphs.dst_id = GetULONG(buffer + 12, bigEndian); + + renderExtension -> data.composite_glyphs.format = GetULONG(buffer + 16, bigEndian); + renderExtension -> data.composite_glyphs.set_id = GetULONG(buffer + 20, bigEndian); + + renderExtension -> data.composite_glyphs.src_x = GetUINT(buffer + 24, bigEndian); + renderExtension -> data.composite_glyphs.src_y = GetUINT(buffer + 26, bigEndian); + + // Since ProtoStep8 (#issue 108) + if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) + { + renderExtension -> data.composite_glyphs.num_elm = *(buffer + 28); + + renderExtension -> data.composite_glyphs.offset_x = GetUINT(buffer + 32, bigEndian); + renderExtension -> data.composite_glyphs.offset_y = GetUINT(buffer + 34, bigEndian); + } + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.composite_glyphs.type + << " size is " << renderExtension -> size_ << " identity size " + << renderExtension -> i_size_ << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.composite_glyphs.type; + *(buffer + 4) = renderExtension -> data.composite_glyphs.op; + + PutULONG(renderExtension -> data.composite_glyphs.src_id, buffer + 8, bigEndian); + PutULONG(renderExtension -> data.composite_glyphs.dst_id, buffer + 12, bigEndian); + + PutULONG(renderExtension -> data.composite_glyphs.format, buffer + 16, bigEndian); + PutULONG(renderExtension -> data.composite_glyphs.set_id, buffer + 20, bigEndian); + + PutUINT(renderExtension -> data.composite_glyphs.src_x, buffer + 24, bigEndian); + PutUINT(renderExtension -> data.composite_glyphs.src_y, buffer + 26, bigEndian); + + // Since ProtoStep8 (#issue 108) + if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) + { + *(buffer + 28) = renderExtension -> data.composite_glyphs.num_elm; + + PutUINT(renderExtension -> data.composite_glyphs.offset_x, buffer + 32, bigEndian); + PutUINT(renderExtension -> data.composite_glyphs.offset_y, buffer + 34, bigEndian); + } + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.composite_glyphs.type + << " size is " << renderExtension -> size_ << " identity size " + << renderExtension -> i_size_ << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + // + // Include minor opcode, size and + // the composite operator in the + // identity. + // + + md5_append(md5_state, buffer + 1, 4); + + // + // Include the format. + // + + md5_append(md5_state, buffer + 16, 4); + + // + // Also include the length of the + // first string. + // + + // Since ProtoStep8 (#issue 108) + if (size >= MESSAGE_OFFSET_IF_PROTO_STEP_8) + { + md5_append(md5_state, buffer + 28, 1); + } +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(renderExtension -> data.composite_glyphs.src_id, + clientCache -> renderSrcPictureCache); + + cachedRenderExtension -> data.composite_glyphs.src_id = + renderExtension -> data.composite_glyphs.src_id; + + encodeBuffer.encodeXidValue(renderExtension -> data.composite_glyphs.dst_id, + clientCache -> renderDstPictureCache); + + cachedRenderExtension -> data.composite_glyphs.dst_id = + renderExtension -> data.composite_glyphs.dst_id; + + encodeBuffer.encodeCachedValue(renderExtension -> data.composite_glyphs.set_id, 29, + clientCache -> renderGlyphSetCache); + + cachedRenderExtension -> data.composite_glyphs.set_id = + renderExtension -> data.composite_glyphs.set_id; + + // + // Src X and Y. + // + // The source X and Y coordinates are + // encoded as differerences in respect + // to the cached message. + // + + unsigned int value; + unsigned int previous; + + // Since ProtoStep8 (#issue 108) + value = renderExtension -> data.composite_glyphs.src_x; + previous = cachedRenderExtension -> data.composite_glyphs.src_x; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderGlyphXCache, 11); + + cachedRenderExtension -> data.composite_glyphs.src_x = value; + + value = renderExtension -> data.composite_glyphs.src_y; + previous = cachedRenderExtension -> data.composite_glyphs.src_y; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderGlyphYCache, 11); + + cachedRenderExtension -> data.composite_glyphs.src_y = value; + + #ifdef TEST + *logofs << name() << ": Encoded source X " + << renderExtension -> data.composite_glyphs.src_x << " source Y " + << renderExtension -> data.composite_glyphs.src_y << ".\n" + << logofs_flush; + #endif + + // Since ProtoStep8 (#issue 108) + if (renderExtension -> size_ >= MESSAGE_OFFSET_IF_PROTO_STEP_8) + { + // + // Offset X and Y. + // + + if (renderExtension -> data.composite_glyphs.offset_x == + renderExtension -> data.composite_glyphs.src_x && + renderExtension -> data.composite_glyphs.offset_y == + renderExtension -> data.composite_glyphs.src_y) + { + encodeBuffer.encodeBoolValue(0); + + cachedRenderExtension -> data.composite_glyphs.offset_x = + renderExtension -> data.composite_glyphs.offset_x; + + cachedRenderExtension -> data.composite_glyphs.offset_y = + renderExtension -> data.composite_glyphs.offset_y; + + #ifdef TEST + *logofs << name() << ": Matched offset X " + << renderExtension -> data.composite_glyphs.offset_x << " offset Y " + << renderExtension -> data.composite_glyphs.offset_y << ".\n" + << logofs_flush; + #endif + } + else + { + encodeBuffer.encodeBoolValue(1); + + value = renderExtension -> data.composite_glyphs.offset_x; + previous = cachedRenderExtension -> data.composite_glyphs.offset_x; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderGlyphXCache, 11); + + cachedRenderExtension -> data.composite_glyphs.offset_x = value; + + value = renderExtension -> data.composite_glyphs.offset_y; + previous = cachedRenderExtension -> data.composite_glyphs.offset_y; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderGlyphYCache, 11); + + cachedRenderExtension -> data.composite_glyphs.offset_y = value; + + #ifdef TEST + *logofs << name() << ": Missed offset X " + << renderExtension -> data.composite_glyphs.offset_x << " offset Y " + << renderExtension -> data.composite_glyphs.offset_y << ".\n" + << logofs_flush; + #endif + } + } + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.composite_glyphs.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(renderExtension -> data.composite_glyphs.src_id, + clientCache -> renderSrcPictureCache); + + decodeBuffer.decodeXidValue(renderExtension -> data.composite_glyphs.dst_id, + clientCache -> renderDstPictureCache); + + decodeBuffer.decodeCachedValue(renderExtension -> data.composite_glyphs.set_id, 29, + clientCache -> renderGlyphSetCache); + + // + // Src X and Y. + // + + unsigned int value; + unsigned int previous; + + // Since ProtoStep8 (#issue 108) + previous = renderExtension -> data.composite_glyphs.src_x; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderGlyphXCache, 11); + + renderExtension -> data.composite_glyphs.src_x = value; + + previous = renderExtension -> data.composite_glyphs.src_y; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderGlyphYCache, 11); + + renderExtension -> data.composite_glyphs.src_y = value; + + // Since ProtoStep8 (#issue 108) + if (renderExtension -> size_ >= MESSAGE_OFFSET_IF_PROTO_STEP_8) + { + // + // Offset X and Y. + // + + decodeBuffer.decodeBoolValue(value); + + if (value == 0) + { + renderExtension -> data.composite_glyphs.offset_x = + renderExtension -> data.composite_glyphs.src_x; + + renderExtension -> data.composite_glyphs.offset_y = + renderExtension -> data.composite_glyphs.src_y; + } + else + { + previous = renderExtension -> data.composite_glyphs.offset_x; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderGlyphXCache, 11); + + renderExtension -> data.composite_glyphs.offset_x = value; + + previous = renderExtension -> data.composite_glyphs.offset_y; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderGlyphYCache, 11); + + renderExtension -> data.composite_glyphs.offset_y = value; + } + } + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.composite_glyphs.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderCompositeGlyphs.h b/nxcomp/src/RenderCompositeGlyphs.h new file mode 100644 index 000000000..1062ee781 --- /dev/null +++ b/nxcomp/src/RenderCompositeGlyphs.h @@ -0,0 +1,100 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderCompositeGlyphs_H +#define RenderCompositeGlyphs_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderCompositeGlyphs" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderCompositeGlyphsStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 28 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Encode the first 8 bytes of the +// data differentially in newer +// protocol versions. +// + +#undef MESSAGE_OFFSET_IF_PROTO_STEP_8 +#define MESSAGE_OFFSET_IF_PROTO_STEP_8 36 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + // Since ProtoStep8 (#issue 108) + unsigned int offset = MESSAGE_OFFSET_IF_PROTO_STEP_8; + + return (size >= offset ? offset : size); + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderCompositeGlyphs_H */ diff --git a/nxcomp/src/RenderCreateGlyphSet.cpp b/nxcomp/src/RenderCreateGlyphSet.cpp new file mode 100644 index 000000000..e3a842de9 --- /dev/null +++ b/nxcomp/src/RenderCreateGlyphSet.cpp @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderCreateGlyphSet.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeNewXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> renderGlyphSetCache, + clientCache -> renderFreeGlyphSetCache); + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 8, bigEndian), 32, + clientCache -> renderFormatCache); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeNewXidValue(value, + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> renderGlyphSetCache, + clientCache -> renderFreeGlyphSetCache); + + PutULONG(value, buffer + 4, bigEndian); + + decodeBuffer.decodeCachedValue(value, 32, + clientCache -> renderFormatCache); + + PutULONG(value, buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.create_set.type = *(buffer + 1); + + renderExtension -> data.create_set.set_id = GetULONG(buffer + 4, bigEndian); + renderExtension -> data.create_set.format = GetULONG(buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.create_set.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.create_set.type; + + PutULONG(renderExtension -> data.create_set.set_id, buffer + 4, bigEndian); + PutULONG(renderExtension -> data.create_set.format, buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.create_set.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + md5_append(md5_state, buffer + 1, 3); + md5_append(md5_state, buffer + 8, 4); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeNewXidValue(renderExtension -> data.create_set.set_id, + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> renderGlyphSetCache, + clientCache -> renderFreeGlyphSetCache); + + cachedRenderExtension -> data.create_set.set_id = + renderExtension -> data.create_set.set_id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.create_set.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeNewXidValue(renderExtension -> data.create_set.set_id, + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> renderGlyphSetCache, + clientCache -> renderFreeGlyphSetCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.create_set.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderCreateGlyphSet.h b/nxcomp/src/RenderCreateGlyphSet.h new file mode 100644 index 000000000..10f5d6699 --- /dev/null +++ b/nxcomp/src/RenderCreateGlyphSet.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderCreateGlyphSet_H +#define RenderCreateGlyphSet_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderCreateGlyphSet" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderCreateGlyphSetStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 12 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 0 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 0 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderCreateGlyphSet_H */ diff --git a/nxcomp/src/RenderCreatePicture.cpp b/nxcomp/src/RenderCreatePicture.cpp new file mode 100644 index 000000000..f3f9f8b8a --- /dev/null +++ b/nxcomp/src/RenderCreatePicture.cpp @@ -0,0 +1,278 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderCreatePicture.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + size = MESSAGE_OFFSET + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeNewXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> renderSrcPictureCache, + clientCache -> renderFreePictureCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), + clientCache -> drawableCache); + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 12, bigEndian), 32, + clientCache -> renderFormatCache); + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 32, + clientCache -> renderValueMaskCache); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeNewXidValue(value, + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> renderSrcPictureCache, + clientCache -> renderFreePictureCache); + + PutULONG(value, buffer + 4, bigEndian); + + decodeBuffer.decodeXidValue(value, + clientCache -> drawableCache); + + PutULONG(value, buffer + 8, bigEndian); + + decodeBuffer.decodeCachedValue(value, 32, + clientCache -> renderFormatCache); + + PutULONG(value, buffer + 12, bigEndian); + + decodeBuffer.decodeCachedValue(value, 32, + clientCache -> renderValueMaskCache); + + PutULONG(value, buffer + 16, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.create_picture.type = *(buffer + 1); + + renderExtension -> data.create_picture.src_id = GetULONG(buffer + 4, bigEndian); + renderExtension -> data.create_picture.dst_id = GetULONG(buffer + 8, bigEndian); + + renderExtension -> data.create_picture.format = GetULONG(buffer + 12, bigEndian); + renderExtension -> data.create_picture.mask = GetULONG(buffer + 16, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.create_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.create_picture.type; + + PutULONG(renderExtension -> data.create_picture.src_id, buffer + 4, bigEndian); + PutULONG(renderExtension -> data.create_picture.dst_id, buffer + 8, bigEndian); + + PutULONG(renderExtension -> data.create_picture.format, buffer + 12, bigEndian); + PutULONG(renderExtension -> data.create_picture.mask, buffer + 16, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.create_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + md5_append(md5_state, buffer + 1, 3); + md5_append(md5_state, buffer + 12, 8); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding new id value " + << renderExtension -> data.create_picture.src_id + << ".\n"; + #endif + + encodeBuffer.encodeNewXidValue(renderExtension -> data.create_picture.src_id, + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> renderSrcPictureCache, + clientCache -> renderFreePictureCache); + + cachedRenderExtension -> data.create_picture.src_id = + renderExtension -> data.create_picture.src_id; + + encodeBuffer.encodeXidValue(renderExtension -> data.create_picture.dst_id, + clientCache -> drawableCache); + + cachedRenderExtension -> data.create_picture.dst_id = + renderExtension -> data.create_picture.dst_id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.create_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeNewXidValue(renderExtension -> data.create_picture.src_id, + clientCache -> lastId, clientCache -> lastIdCache, + clientCache -> renderSrcPictureCache, + clientCache -> renderFreePictureCache); + + decodeBuffer.decodeXidValue(renderExtension -> data.create_picture.dst_id, + clientCache -> drawableCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.create_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderCreatePicture.h b/nxcomp/src/RenderCreatePicture.h new file mode 100644 index 000000000..ae2f583a0 --- /dev/null +++ b/nxcomp/src/RenderCreatePicture.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderCreatePicture_H +#define RenderCreatePicture_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderCreatePicture" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderCreatePictureStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 20 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderCreatePicture_H */ diff --git a/nxcomp/src/RenderExtension.cpp b/nxcomp/src/RenderExtension.cpp new file mode 100644 index 000000000..64761bc05 --- /dev/null +++ b/nxcomp/src/RenderExtension.cpp @@ -0,0 +1,427 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "NXrender.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +#include "RenderExtension.h" + +#include "RenderGenericRequest.h" +#include "RenderCreatePicture.h" +#include "RenderChangePicture.h" +#include "RenderFreePicture.h" +#include "RenderPictureClip.h" +#include "RenderPictureTransform.h" +#include "RenderPictureFilter.h" +#include "RenderCreateGlyphSet.h" +#include "RenderFreeGlyphSet.h" +#include "RenderAddGlyphs.h" +#include "RenderComposite.h" +#include "RenderCompositeGlyphs.h" +#include "RenderFillRectangles.h" +#include "RenderTrapezoids.h" +#include "RenderTriangles.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Constructor and destructor. +// + +RenderExtensionStore::RenderExtensionStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = RENDEREXTENSION_ENABLE_CACHE; + enableData = RENDEREXTENSION_ENABLE_DATA; + enableSplit = RENDEREXTENSION_ENABLE_SPLIT; + enableCompress = RENDEREXTENSION_ENABLE_COMPRESS; + + generic_ = new RenderGenericRequestStore(); + + for (int i = 0; i < RENDEREXTENSION_MINOR_OPCODE_LIMIT; i++) + { + minors_[i] = generic_; + } + + minors_[X_RenderChangePicture] = new RenderChangePictureStore(); + minors_[X_RenderFillRectangles] = new RenderFillRectanglesStore(); + minors_[X_RenderAddGlyphs] = new RenderAddGlyphsStore(); + + // Since ProtoStep7 (#issue 108) + minors_[X_RenderCreatePicture] = new RenderCreatePictureStore(); + minors_[X_RenderFreePicture] = new RenderFreePictureStore(); + minors_[X_RenderSetPictureClipRectangles] = new RenderPictureClipStore(); + minors_[X_RenderCreateGlyphSet] = new RenderCreateGlyphSetStore(); + minors_[X_RenderComposite] = new RenderCompositeStore(); + minors_[X_RenderCompositeGlyphs8] = new RenderCompositeGlyphsStore(); + minors_[X_RenderCompositeGlyphs16] = new RenderCompositeGlyphsStore(); + minors_[X_RenderCompositeGlyphs32] = new RenderCompositeGlyphsStore(); + + minors_[X_RenderSetPictureTransform] = new RenderPictureTransformStore(); + minors_[X_RenderSetPictureFilter] = new RenderPictureFilterStore(); + minors_[X_RenderFreeGlyphSet] = new RenderFreeGlyphSetStore(); + minors_[X_RenderTrapezoids] = new RenderTrapezoidsStore(); + minors_[X_RenderTriangles] = new RenderTrianglesStore(); + + dataLimit = RENDEREXTENSION_DATA_LIMIT; + dataOffset = RENDEREXTENSION_DATA_OFFSET; + + // Since ProtoStep7 (#issue 108) + cacheSlots = RENDEREXTENSION_CACHE_SLOTS_IF_PROTO_STEP_7; + + cacheThreshold = RENDEREXTENSION_CACHE_THRESHOLD; + cacheLowerThreshold = RENDEREXTENSION_CACHE_LOWER_THRESHOLD; + + opcode_ = X_NXInternalRenderExtension; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +RenderExtensionStore::~RenderExtensionStore() +{ + for (int i = 0; i < RENDEREXTENSION_MINOR_OPCODE_LIMIT; i++) + { + if (minors_[i] != generic_) + { + delete minors_[i]; + } + } + + delete generic_; + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +int RenderExtensionStore::validateMessage(const unsigned char *buffer, int size) +{ + #ifdef TEST + *logofs << name() << ": Encoding message OPCODE#" + << (unsigned) *buffer << " MINOR#" << (unsigned) + *(buffer + 1) << " with size " << size + << ".\n" << logofs_flush; + #endif + + return (size >= control -> MinimumMessageSize && + size <= control -> MaximumMessageSize); +} + +// +// Here are the methods to handle the messages' content. +// + +int RenderExtensionStore::identitySize(const unsigned char *buffer, unsigned int size) +{ + return minors_[*(buffer + 1)] -> identitySize(buffer, size); +} + +int RenderExtensionStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + encodeBuffer.encodeOpcodeValue(*(buffer + 1), + ((ClientCache *) channelCache) -> renderOpcodeCache); + + minors_[*(buffer + 1)] -> encodeMessage(encodeBuffer, buffer, size, + bigEndian, channelCache); + + return 1; +} + +int RenderExtensionStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + unsigned char type; + + decodeBuffer.decodeOpcodeValue(type, + ((ClientCache *) channelCache) -> renderOpcodeCache); + + minors_[type] -> decodeMessage(decodeBuffer, buffer, size, type, + bigEndian, writeBuffer, channelCache); + + return 1; +} + +int RenderExtensionStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + return minors_[*(buffer + 1)] -> parseIdentity(message, buffer, size, bigEndian); +} + +int RenderExtensionStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + return minors_[((RenderExtensionMessage *) message) -> data.any.type] -> + unparseIdentity(message, buffer, size, bigEndian); +} + +void RenderExtensionStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + minors_[*(buffer + 1)] -> identityChecksum(message, buffer, size, md5_state_, bigEndian); +} + +void RenderExtensionStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + minors_[((RenderExtensionMessage *) message) -> data.any.type] -> + updateIdentity(encodeBuffer, message, cachedMessage, channelCache); +} + +void RenderExtensionStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + minors_[((RenderExtensionMessage *) message) -> data.any.type] -> + updateIdentity(decodeBuffer, message, channelCache); +} + +void RenderExtensionStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + #ifdef WARNING + *logofs << name() << ": WARNING! Dump of identity not implemented.\n" + << logofs_flush; + #endif + + #endif +} + +// +// TODO: The following encoding and decoding functions +// could be generalized further, for example by passing +// the pointer to the data cache, the number of caches +// made available by the caller and the first cache to +// iterate through. +// + +void RenderMinorExtensionStore::encodeLongData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeLongData(buffer + offset, size - offset); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - offset + << " bytes of long data.\n" << logofs_flush; + #endif +} + +void RenderMinorExtensionStore::encodeIntData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeIntData(buffer + offset, size - offset); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - offset + << " bytes of int data.\n" << logofs_flush; + #endif +} + +void RenderMinorExtensionStore::encodeCharData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(buffer + offset, size - offset); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - offset + << " bytes of text data.\n" << logofs_flush; + #endif +} + +void RenderMinorExtensionStore::decodeLongData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeLongData(buffer + offset, size - offset); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - offset + << " bytes of long data.\n" << logofs_flush; + #endif +} + +void RenderMinorExtensionStore::decodeIntData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeIntData(buffer + offset, size - offset); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - offset + << " bytes of int data.\n" << logofs_flush; + #endif +} + +void RenderMinorExtensionStore::decodeCharData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(buffer + offset, size - offset); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - offset + << " bytes of text data.\n" << logofs_flush; + #endif +} + +void RenderMinorExtensionStore::parseIntData(const Message *message, const unsigned char *buffer, + unsigned int offset, unsigned int size, + int bigEndian) const +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + unsigned int last = ((unsigned) message -> i_size_ > size ? size : message -> i_size_); + + for (unsigned int i = offset, c = (offset - 4) % 16; i < last; i += 2) + { + #ifdef DEBUG + *logofs << name() << ": Parsing int with i = " << i << " c = " + << c << ".\n" << logofs_flush; + #endif + + renderExtension -> data.any.short_data[c] = GetUINT(buffer + i, bigEndian); + + if (++c == 16) c = 0; + } +} + +void RenderMinorExtensionStore::unparseIntData(const Message *message, unsigned char *buffer, + unsigned int offset, unsigned int size, + int bigEndian) const +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + unsigned int last = ((unsigned) message -> i_size_ > size ? size : message -> i_size_); + + for (unsigned int i = offset, c = (offset - 4) % 16; i < last; i += 2) + { + #ifdef DEBUG + *logofs << name() << ": Unparsing int with i = " << i << " c = " + << c << ".\n" << logofs_flush; + #endif + + PutUINT(renderExtension -> data.any.short_data[c], buffer + i, bigEndian); + + if (++c == 16) c = 0; + } +} + +void RenderMinorExtensionStore::updateIntData(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, unsigned int offset, + unsigned int size, ChannelCache *channelCache) const +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int last = ((unsigned) message -> i_size_ > size ? size : message -> i_size_); + + for (unsigned int i = offset, c = (offset - 4) % 16; i < last; i += 2) + { + #ifdef DEBUG + *logofs << name() << ": Encoding int update with i = " << i + << " c = " << c << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(renderExtension -> data.any.short_data[c], 16, + *clientCache -> renderDataCache[c]); + + cachedRenderExtension -> data.any.short_data[c] = + renderExtension -> data.any.short_data[c]; + + if (++c == 16) c = 0; + } +} + +void RenderMinorExtensionStore::updateIntData(DecodeBuffer &decodeBuffer, const Message *message, + unsigned int offset, unsigned int size, + ChannelCache *channelCache) const +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int last = ((unsigned) message -> i_size_ > size ? size : message -> i_size_); + + unsigned int value; + + for (unsigned int i = offset, c = (offset - 4) % 16; i < last; i += 2) + { + #ifdef DEBUG + *logofs << name() << ": Decoding int update with i = " << i + << " c = " << c << ".\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache -> renderDataCache[c]); + + renderExtension -> data.any.short_data[c] = value; + + if (++c == 16) c = 0; + } +} diff --git a/nxcomp/src/RenderExtension.h b/nxcomp/src/RenderExtension.h new file mode 100644 index 000000000..aa9db1b55 --- /dev/null +++ b/nxcomp/src/RenderExtension.h @@ -0,0 +1,504 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderExtension_H +#define RenderExtension_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Compression of data part is not enabled as +// most messages of this type are smaller than +// the current data size compression threshold. +// + +#define RENDEREXTENSION_ENABLE_CACHE 1 +#define RENDEREXTENSION_ENABLE_DATA 0 +#define RENDEREXTENSION_ENABLE_SPLIT 0 +#define RENDEREXTENSION_ENABLE_COMPRESS 0 + +#define RENDEREXTENSION_DATA_LIMIT 6144 +#define RENDEREXTENSION_DATA_OFFSET 36 + +#define RENDEREXTENSION_CACHE_THRESHOLD 20 +#define RENDEREXTENSION_CACHE_LOWER_THRESHOLD 10 + +#define RENDEREXTENSION_CACHE_SLOTS_IF_PROTO_STEP_7 8000 + +// +// Used to build the table of minor opcodes. +// + +#define RENDEREXTENSION_MINOR_OPCODE_LIMIT 256 + +// +// The message class. +// + +class RenderMinorExtensionStore; + +class RenderExtensionMessage : public Message +{ + friend class RenderExtensionStore; + friend class RenderMinorExtensionStore; + + friend class RenderGenericRequestStore; + friend class RenderCreatePictureStore; + friend class RenderChangePictureStore; + friend class RenderFreePictureStore; + friend class RenderPictureClipStore; + friend class RenderPictureTransformStore; + friend class RenderPictureFilterStore; + friend class RenderCreateGlyphSetStore; + friend class RenderFreeGlyphSetStore; + friend class RenderAddGlyphsStore; + friend class RenderCompositeStore; + friend class RenderCompositeGlyphsStore; + friend class RenderFillRectanglesStore; + friend class RenderTrapezoidsStore; + friend class RenderTrianglesStore; + + public: + + RenderExtensionMessage() + { + } + + ~RenderExtensionMessage() + { + } + + // + // We consider for this message a data offset of 36, + // that is size of the biggest among all requests of + // this extension. The most common requests have a + // specific differential encoding, others are simply + // encoded through an array of int or char caches. + // + + private: + + union + { + struct + { + unsigned char type; + + unsigned char char_data[32]; + unsigned short short_data[16]; + unsigned short long_data[8]; + } + any; + + struct + { + unsigned char type; + + unsigned int src_id; + unsigned int dst_id; + + unsigned int format; + unsigned int mask; + } + create_picture; + + struct + { + unsigned char type; + + unsigned int src_id; + } + change_picture; + + struct + { + unsigned char type; + + unsigned int src_id; + } + free_picture; + + struct + { + unsigned char type; + + unsigned int src_id; + + unsigned short src_x; + unsigned short src_y; + } + picture_clip; + + struct + { + unsigned char type; + + unsigned int src_id; + } + picture_transform; + + struct + { + unsigned char type; + + unsigned int src_id; + unsigned int num_elm; + } + picture_filter; + + struct + { + unsigned char type; + + unsigned int set_id; + unsigned int format; + } + create_set; + + struct + { + unsigned char type; + + unsigned int set_id; + } + free_set; + + struct + { + unsigned char type; + + unsigned int set_id; + unsigned int num_elm; + } + add_glyphs; + + struct + { + unsigned char type; + + unsigned char op; + + unsigned int src_id; + unsigned int msk_id; + unsigned int dst_id; + + unsigned short src_x; + unsigned short src_y; + + unsigned short msk_x; + unsigned short msk_y; + + unsigned short dst_x; + unsigned short dst_y; + + unsigned short width; + unsigned short height; + } + composite; + + struct + { + unsigned char type; + + unsigned char op; + + unsigned char num_elm; + + unsigned int src_id; + unsigned int dst_id; + + unsigned int format; + unsigned int set_id; + + unsigned short src_x; + unsigned short src_y; + + unsigned short offset_x; + unsigned short offset_y; + } + composite_glyphs; + + struct + { + unsigned char type; + + unsigned char op; + + unsigned int dst_id; + } + fill_rectangles; + + struct + { + unsigned char type; + + unsigned char op; + + unsigned int src_id; + unsigned int dst_id; + + unsigned int format; + + unsigned short src_x; + unsigned short src_y; + } + trapezoids; + + struct + { + unsigned char type; + + unsigned char op; + + unsigned int src_id; + unsigned int dst_id; + + unsigned int format; + + unsigned short src_x; + unsigned short src_y; + } + triangles; + + struct + { + unsigned char type; + + unsigned char op; + + unsigned char num_elm; + + unsigned int src_id; + unsigned int dst_id; + + unsigned int format; + unsigned int set_id; + + unsigned short src_x; + unsigned short src_y; + + unsigned short delta_x; + unsigned short delta_y; + } + composite_glyphs_compat; + + } + data; +}; + +class RenderExtensionStore : public MessageStore +{ + public: + + RenderExtensionStore(StaticCompressor *compressor); + + virtual ~RenderExtensionStore(); + + virtual const char *name() const + { + return "RenderExtension"; + } + + virtual unsigned char opcode() const + { + return opcode_; + } + + virtual unsigned int storage() const + { + return sizeof(RenderExtensionMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new RenderExtensionMessage(); + } + + virtual Message *create(const Message &message) const + { + return new RenderExtensionMessage((const RenderExtensionMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (RenderExtensionMessage *) message; + } + + // + // Determine if the message must be stored + // in the cache. + // + + virtual int validateMessage(const unsigned char *buffer, int size); + + // + // Since protocol step 5 these methods are + // specialized in their minor opcode stores. + // + + virtual int identitySize(const unsigned char *buffer, unsigned int size); + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; + + private: + + unsigned char opcode_; + + // + // Keep pointers to specialized classes. + // + + RenderMinorExtensionStore *minors_[RENDEREXTENSION_MINOR_OPCODE_LIMIT]; + + RenderMinorExtensionStore *generic_; +}; + +class RenderMinorExtensionStore : public MinorMessageStore +{ + public: + + virtual const char *name() const = 0; + + virtual int identitySize(const unsigned char *buffer, unsigned int size) = 0; + + virtual int encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const = 0; + + virtual int decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, unsigned char type, int bigEndian, + WriteBuffer *writeBuffer, ChannelCache *channelCache) const = 0; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const = 0; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const = 0; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const = 0; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const = 0; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, md5_state_t *md5_state, + int bigEndian) const = 0; + + // + // Internal encode and decode utilities. + // + + protected: + + void encodeLongData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + void encodeIntData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + void encodeCharData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + void decodeLongData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + void decodeIntData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + void decodeCharData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int offset, unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + /* + * The following methods are only used in the + * encoding of the generic render request. To + * be removed in future. + */ + + void parseIntData(const Message *message, const unsigned char *buffer, + unsigned int offset, unsigned int size, + int bigEndian) const; + + void unparseIntData(const Message *message, unsigned char *buffer, + unsigned int offset, unsigned int size, + int bigEndian) const; + + void updateIntData(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, unsigned int offset, + unsigned int size, ChannelCache *channelCache) const; + + void updateIntData(DecodeBuffer &decodeBuffer, const Message *message, + unsigned int offset, unsigned int size, + ChannelCache *channelCache) const; +}; + +#endif /* RenderExtension_H */ diff --git a/nxcomp/src/RenderFillRectangles.cpp b/nxcomp/src/RenderFillRectangles.cpp new file mode 100644 index 000000000..db05887ab --- /dev/null +++ b/nxcomp/src/RenderFillRectangles.cpp @@ -0,0 +1,237 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderFillRectangles.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + // + // The color structure (4 components, 2 bytes + // each) is included in the data part, so that + // it gets into the checksum. The rectangles + // are in the format x, y, width, height with + // 2 bytes per each field, so each request is + // at least 12 + 8 + 8 = 28 bytes long. + // + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + size = MESSAGE_OFFSET + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), + clientCache -> renderSrcPictureCache); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + decodeBuffer.decodeXidValue(value, clientCache -> renderSrcPictureCache); + + PutULONG(value, buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + encodeIntData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + decodeIntData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.fill_rectangles.type = *(buffer + 1); + renderExtension -> data.fill_rectangles.op = *(buffer + 4); + + renderExtension -> data.fill_rectangles.dst_id = GetULONG(buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.fill_rectangles.type << " size is " + << renderExtension -> size_ << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.fill_rectangles.type; + *(buffer + 4) = renderExtension -> data.fill_rectangles.op; + + PutULONG(renderExtension -> data.fill_rectangles.dst_id, buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.fill_rectangles.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + md5_append(md5_state, buffer + 1, 4); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(renderExtension -> data.fill_rectangles.dst_id, + clientCache -> renderSrcPictureCache); + + cachedRenderExtension -> data.fill_rectangles.dst_id = + renderExtension -> data.fill_rectangles.dst_id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.fill_rectangles.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(renderExtension -> data.fill_rectangles.dst_id, + clientCache -> renderSrcPictureCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.fill_rectangles.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderFillRectangles.h b/nxcomp/src/RenderFillRectangles.h new file mode 100644 index 000000000..9efaeffa8 --- /dev/null +++ b/nxcomp/src/RenderFillRectangles.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderFillRectangles_H +#define RenderFillRectangles_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderFillRectangles" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderFillRectanglesStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 12 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderFillRectangles_H */ diff --git a/nxcomp/src/RenderFreeGlyphSet.cpp b/nxcomp/src/RenderFreeGlyphSet.cpp new file mode 100644 index 000000000..88dfb791a --- /dev/null +++ b/nxcomp/src/RenderFreeGlyphSet.cpp @@ -0,0 +1,166 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderFreeGlyphSet.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeFreeXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> renderFreeGlyphSetCache); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + unsigned int value; + + ClientCache *clientCache = (ClientCache *) channelCache; + + *(buffer + 1) = type; + + decodeBuffer.decodeFreeXidValue(value, + clientCache -> renderFreeGlyphSetCache); + + PutULONG(value, buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.free_set.type = *(buffer + 1); + + renderExtension -> data.free_set.set_id = GetULONG(buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.free_set.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.free_set.type; + + PutULONG(renderExtension -> data.free_set.set_id, buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.free_set.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + md5_append(md5_state, buffer + 1, 3); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeFreeXidValue(renderExtension -> data.free_set.set_id, + clientCache -> renderFreeGlyphSetCache); + + cachedRenderExtension -> data.free_set.set_id = + renderExtension -> data.free_set.set_id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.free_set.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeFreeXidValue(renderExtension -> data.free_set.set_id, + clientCache -> renderFreeGlyphSetCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.free_set.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderFreeGlyphSet.h b/nxcomp/src/RenderFreeGlyphSet.h new file mode 100644 index 000000000..8817e8d99 --- /dev/null +++ b/nxcomp/src/RenderFreeGlyphSet.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderFreeGlyphSet_H +#define RenderFreeGlyphSet_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderFreeGlyphSet" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderFreeGlyphSetStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 8 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 0 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 0 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderFreeGlyphSet_H */ diff --git a/nxcomp/src/RenderFreePicture.cpp b/nxcomp/src/RenderFreePicture.cpp new file mode 100644 index 000000000..31662a7e2 --- /dev/null +++ b/nxcomp/src/RenderFreePicture.cpp @@ -0,0 +1,166 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderFreePicture.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeFreeXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> renderFreePictureCache); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + unsigned int value; + + ClientCache *clientCache = (ClientCache *) channelCache; + + *(buffer + 1) = type; + + decodeBuffer.decodeFreeXidValue(value, + clientCache -> renderFreePictureCache); + + PutULONG(value, buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.free_picture.type = *(buffer + 1); + + renderExtension -> data.free_picture.src_id = GetULONG(buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.free_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.free_picture.type; + + PutULONG(renderExtension -> data.free_picture.src_id, buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.free_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + md5_append(md5_state, buffer + 1, 3); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeFreeXidValue(renderExtension -> data.free_picture.src_id, + clientCache -> renderFreePictureCache); + + cachedRenderExtension -> data.free_picture.src_id = + renderExtension -> data.free_picture.src_id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.free_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeFreeXidValue(renderExtension -> data.free_picture.src_id, + clientCache -> renderFreePictureCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.free_picture.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderFreePicture.h b/nxcomp/src/RenderFreePicture.h new file mode 100644 index 000000000..b50191a72 --- /dev/null +++ b/nxcomp/src/RenderFreePicture.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderFreePicture_H +#define RenderFreePicture_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderFreePicture" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderFreePictureStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 8 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 0 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 0 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderFreePicture_H */ diff --git a/nxcomp/src/RenderGenericRequest.cpp b/nxcomp/src/RenderGenericRequest.cpp new file mode 100644 index 000000000..cff34e61e --- /dev/null +++ b/nxcomp/src/RenderGenericRequest.cpp @@ -0,0 +1,270 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "NXrender.h" + +#include "RenderExtension.h" +#include "RenderGenericRequest.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Here are the methods to handle the messages' content. +// + +int RenderGenericRequestStore::encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message.\n" + << logofs_flush; + + unsigned char type = *(buffer + 1); + + #endif + + encodeBuffer.encodeCachedValue(size >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef DEBUG + *logofs << name() << ": Encoding full unhandled message. " + << "Type is " << (unsigned int) type << " size is " + << size << ".\n" << logofs_flush; + #endif + + encodeIntData(encodeBuffer, buffer, 4, size, + bigEndian, clientCache); + + #ifdef DEBUG + *logofs << name() << ": Encoded full message.\n" + << logofs_flush; + #endif + + return 1; +} + +int RenderGenericRequestStore::decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, unsigned char type, int bigEndian, + WriteBuffer *writeBuffer, ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message.\n" + << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + size <<= 2; + + buffer = writeBuffer -> addMessage(size); + + *(buffer + 1) = type; + + #ifdef DEBUG + *logofs << name() << ": Decoding full unhandled message. " + << "Type is " << (unsigned int) type << " size is " + << size << ".\n" << logofs_flush; + #endif + + decodeIntData(decodeBuffer, buffer, 4, size, + bigEndian, clientCache); + + #ifdef DEBUG + *logofs << name() << ": Decoded full message.\n" + << logofs_flush; + #endif + + return 1; +} + +void RenderGenericRequestStore::encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ +} + +void RenderGenericRequestStore::decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ +} + +int RenderGenericRequestStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + #ifdef DEBUG + *logofs << name() << ": Parsing identity for message at " + << this << ".\n" << logofs_flush; + #endif + + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + unsigned char type = *(buffer + 1); + + renderExtension -> data.any.type = type; + + #ifdef DEBUG + *logofs << name() << ": Parsing unhandled identity. " + << "Type is " << (unsigned int) renderExtension -> data.any.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif + + parseIntData(message, buffer, 4, size, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int RenderGenericRequestStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + #ifdef DEBUG + *logofs << name() << ": Unparsing identity for message at " + << this << ".\n" << logofs_flush; + #endif + + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + unsigned char type = renderExtension -> data.any.type; + + *(buffer + 1) = type; + + #ifdef DEBUG + *logofs << name() << ": Unparsing unhandled identity. " + << "Type is " << (unsigned int) renderExtension -> data.any.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif + + unparseIntData(message, buffer, 4, size, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void RenderGenericRequestStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, md5_state_t *md5_state, + int bigEndian) const +{ + // + // Include the minor opcode in the checksum. + // Because the data offset can be beyond the + // real end of the message, we need to include + // the size or we will match any message whose + // size is less or equal to the data offset. + // + + md5_append(md5_state, buffer + 1, 3); +} + +void RenderGenericRequestStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + // + // Encode the variant part. + // + + #ifdef DEBUG + *logofs << name() << ": Updating identity for message at " + << this << ".\n" << logofs_flush; + #endif + + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + #ifdef DEBUG + *logofs << name() << ": Encoding unhandled update. " + << "Type is " << (unsigned int) renderExtension -> data.any.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif + + updateIntData(encodeBuffer, message, cachedMessage, 4, + renderExtension -> size_, channelCache); + + #ifdef DEBUG + *logofs << name() << ": Updated identity for message at " + << this << ".\n" << logofs_flush; + #endif +} + +void RenderGenericRequestStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + #ifdef DEBUG + *logofs << name() << ": Updating identity for message at " + << this << ".\n" << logofs_flush; + #endif + + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + #ifdef DEBUG + *logofs << name() << ": Decoding unhandled update. " + << "Type is " << (unsigned int) renderExtension -> data.any.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif + + updateIntData(decodeBuffer, message, 4, + renderExtension -> size_, channelCache); + + #ifdef DEBUG + *logofs << name() << ": Updated identity for message at " + << this << ".\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/RenderGenericRequest.h b/nxcomp/src/RenderGenericRequest.h new file mode 100644 index 000000000..fdf5ca876 --- /dev/null +++ b/nxcomp/src/RenderGenericRequest.h @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderGenericRequest_H +#define RenderGenericRequest_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +class RenderGenericRequestStore : public RenderMinorExtensionStore +{ + public: + + virtual const char *name() const + { + return "RenderGenericRequest"; + } + + virtual int identitySize(const unsigned char *buffer, unsigned int size) + { + return RENDEREXTENSION_DATA_OFFSET; + } + + virtual int encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, unsigned char type, int bigEndian, + WriteBuffer *writeBuffer, ChannelCache *channelCache) const; + + virtual void encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual void decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, md5_state_t *md5_state, + int bigEndian) const; +}; + +#endif /* RenderGenericRequest_H */ diff --git a/nxcomp/src/RenderMinorExtensionHeaders.h b/nxcomp/src/RenderMinorExtensionHeaders.h new file mode 100644 index 000000000..b7f6efc5a --- /dev/null +++ b/nxcomp/src/RenderMinorExtensionHeaders.h @@ -0,0 +1,42 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderMinorExtensionHeaders_H +#define RenderMinorExtensionHeaders_H + +#include "NXrender.h" + +#include "Message.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +#include "RenderExtension.h" + +#endif /* RenderMinorExtensionHeaders_H */ diff --git a/nxcomp/src/RenderMinorExtensionMethods.h b/nxcomp/src/RenderMinorExtensionMethods.h new file mode 100644 index 000000000..d272337e0 --- /dev/null +++ b/nxcomp/src/RenderMinorExtensionMethods.h @@ -0,0 +1,81 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +// +// This file is included multiple times, +// one for each message inheriting the +// parent class. +// + +public: + +#if MESSAGE_HAS_SIZE + +virtual void encodeSize(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + +virtual void decodeSize(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, unsigned char type, int bigEndian, + WriteBuffer *writeBuffer, ChannelCache *channelCache) const; + +#endif + +#if MESSAGE_HAS_DATA + +virtual void encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + +virtual void decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, + unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + +#endif + +virtual int encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + +virtual int decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, unsigned char type, int bigEndian, + WriteBuffer *writeBuffer, ChannelCache *channelCache) const; + +virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + +virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + +virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + +virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + +virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, md5_state_t *md5_state, + int bigEndian) const; diff --git a/nxcomp/src/RenderMinorExtensionTags.h b/nxcomp/src/RenderMinorExtensionTags.h new file mode 100644 index 000000000..c24a99638 --- /dev/null +++ b/nxcomp/src/RenderMinorExtensionTags.h @@ -0,0 +1,194 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderMinorExtensionTags_H +#define RenderMinorExtensionTags_H + +// +// Set in the message header file. +// + +#if MESSAGE_HAS_SIZE + +#define MESSAGE_ENCODE_SIZE encodeSize(encodeBuffer, buffer, size, bigEndian, channelCache) +#define MESSAGE_DECODE_SIZE decodeSize(decodeBuffer, buffer, size, type, bigEndian, writeBuffer, channelCache) + +#else + +#define MESSAGE_ENCODE_SIZE +#define MESSAGE_DECODE_SIZE size = MESSAGE_OFFSET; buffer = writeBuffer -> addMessage(size); + +#endif + +#if MESSAGE_HAS_DATA + +#define MESSAGE_ENCODE_DATA encodeData(encodeBuffer, buffer, size, bigEndian, channelCache) +#define MESSAGE_DECODE_DATA decodeData(decodeBuffer, buffer, size, bigEndian, channelCache) + +#else + +#define MESSAGE_ENCODE_DATA +#define MESSAGE_DECODE_DATA + +#endif + +// +// Prologue an epilogue of the message +// handling functions. +// + +#define MESSAGE_BEGIN_ENCODE_SIZE \ +\ +void MESSAGE_STORE::encodeSize(EncodeBuffer &encodeBuffer, const unsigned char *buffer, \ + const unsigned int size, int bigEndian, \ + ChannelCache *channelCache) const \ +{ + +#define MESSAGE_END_ENCODE_SIZE \ +\ +} + +#define MESSAGE_BEGIN_DECODE_SIZE \ +\ +void MESSAGE_STORE::decodeSize(DecodeBuffer &decodeBuffer, unsigned char *&buffer, \ + unsigned int &size, unsigned char type, int bigEndian, \ + WriteBuffer *writeBuffer, ChannelCache *channelCache) const \ +{ + +#define MESSAGE_END_DECODE_SIZE \ +\ +} + +#define MESSAGE_BEGIN_ENCODE_MESSAGE \ +\ +int MESSAGE_STORE::encodeMessage(EncodeBuffer &encodeBuffer, const unsigned char *buffer, \ + const unsigned int size, int bigEndian, \ + ChannelCache *channelCache) const \ +{ \ + MESSAGE_ENCODE_SIZE; + + +#define MESSAGE_END_ENCODE_MESSAGE \ +\ + MESSAGE_ENCODE_DATA; \ +\ + return 1; \ +} + +#define MESSAGE_BEGIN_DECODE_MESSAGE \ +\ +int MESSAGE_STORE::decodeMessage(DecodeBuffer &decodeBuffer, unsigned char *&buffer, \ + unsigned int &size, unsigned char type, int bigEndian, \ + WriteBuffer *writeBuffer, ChannelCache *channelCache) const \ +{ \ + MESSAGE_DECODE_SIZE; + + +#define MESSAGE_END_DECODE_MESSAGE \ +\ + MESSAGE_DECODE_DATA; \ +\ + return 1; \ +} + +#define MESSAGE_BEGIN_ENCODE_DATA \ +\ +void MESSAGE_STORE::encodeData(EncodeBuffer &encodeBuffer, const unsigned char *buffer, \ + unsigned int size, int bigEndian, \ + ChannelCache *channelCache) const \ +{ + +#define MESSAGE_END_ENCODE_DATA \ +\ +} + +#define MESSAGE_BEGIN_DECODE_DATA \ +\ +void MESSAGE_STORE::decodeData(DecodeBuffer &decodeBuffer, unsigned char *buffer, \ + unsigned int size, int bigEndian, \ + ChannelCache *channelCache) const \ +{ + +#define MESSAGE_END_DECODE_DATA \ +\ +} + +#define MESSAGE_BEGIN_PARSE_IDENTITY \ +\ +int MESSAGE_STORE::parseIdentity(Message *message, const unsigned char *buffer, \ + unsigned int size, int bigEndian) const \ +{ + +#define MESSAGE_END_PARSE_IDENTITY \ +\ + return 1; \ +\ +} + +#define MESSAGE_BEGIN_UNPARSE_IDENTITY \ +\ +int MESSAGE_STORE::unparseIdentity(const Message *message, unsigned char *buffer, \ + unsigned int size, int bigEndian) const \ +{ + +#define MESSAGE_END_UNPARSE_IDENTITY \ +\ + return 1; \ +\ +} + +#define MESSAGE_BEGIN_IDENTITY_CHECKSUM \ +\ +void MESSAGE_STORE::identityChecksum(const Message *message, const unsigned char *buffer, \ + unsigned int size, md5_state_t *md5_state, \ + int bigEndian) const \ +{ + +#define MESSAGE_END_IDENTITY_CHECKSUM \ +\ +} + +#define MESSAGE_BEGIN_ENCODE_UPDATE \ +\ +void MESSAGE_STORE::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, \ + const Message *cachedMessage, \ + ChannelCache *channelCache) const \ +{ + +#define MESSAGE_END_ENCODE_UPDATE \ +\ +} + +#define MESSAGE_BEGIN_DECODE_UPDATE \ +\ +void MESSAGE_STORE::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, \ + ChannelCache *channelCache) const \ +{ + +#define MESSAGE_END_DECODE_UPDATE \ +\ +} + +#endif /* RenderMinorExtensionTags_H */ diff --git a/nxcomp/src/RenderPictureClip.cpp b/nxcomp/src/RenderPictureClip.cpp new file mode 100644 index 000000000..0d6b505eb --- /dev/null +++ b/nxcomp/src/RenderPictureClip.cpp @@ -0,0 +1,303 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderPictureClip.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + // + // The data is constituted by a number of + // rectangles. Each rectangle is in the + // format x, y, width, height with 2 bytes + // per each field, so each request is at + // least 12 + 8 = 20 bytes long. + // + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + size = MESSAGE_OFFSET + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> renderSrcPictureCache); + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 8, bigEndian), + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 10, bigEndian), + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeXidValue(value, + clientCache -> renderSrcPictureCache); + + PutULONG(value, buffer + 4, bigEndian); + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + PutUINT(clientCache -> renderLastX, buffer + 8, bigEndian); + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + PutUINT(clientCache -> renderLastY, buffer + 10, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + encodeIntData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + decodeIntData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.picture_clip.type = *(buffer + 1); + + renderExtension -> data.picture_clip.src_id = GetULONG(buffer + 4, bigEndian); + + renderExtension -> data.picture_clip.src_x = GetUINT(buffer + 8, bigEndian); + renderExtension -> data.picture_clip.src_y = GetUINT(buffer + 10, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.picture_clip.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.picture_clip.type; + + PutULONG(renderExtension -> data.picture_clip.src_id, buffer + 4, bigEndian); + + PutUINT(renderExtension -> data.picture_clip.src_x, buffer + 8, bigEndian); + PutUINT(renderExtension -> data.picture_clip.src_y, buffer + 10, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.picture_clip.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + // + // Encode the picture id and the + // source x and y differentially. + // + + md5_append(md5_state, buffer + 1, 3); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(renderExtension -> data.picture_clip.src_id, + clientCache -> renderSrcPictureCache); + + cachedRenderExtension -> data.picture_clip.src_id = + renderExtension -> data.picture_clip.src_id; + + // + // The source x and y coordinates are + // encoded as differerences in respect + // to the previous cached value. + // + + unsigned int value; + unsigned int previous; + + value = renderExtension -> data.picture_clip.src_x; + previous = cachedRenderExtension -> data.picture_clip.src_x; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderXCache, 11); + + cachedRenderExtension -> data.picture_clip.src_x = value; + + value = renderExtension -> data.picture_clip.src_y; + previous = cachedRenderExtension -> data.picture_clip.src_y; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderYCache, 11); + + cachedRenderExtension -> data.picture_clip.src_y = value; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.picture_clip.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(renderExtension -> data.picture_clip.src_id, + clientCache -> renderSrcPictureCache); + + unsigned int value; + unsigned int previous; + + previous = renderExtension -> data.picture_clip.src_x; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderXCache, 11); + + renderExtension -> data.picture_clip.src_x = value; + + previous = renderExtension -> data.picture_clip.src_y; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderYCache, 11); + + renderExtension -> data.picture_clip.src_y = value; + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.picture_clip.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderPictureClip.h b/nxcomp/src/RenderPictureClip.h new file mode 100644 index 000000000..bd811dfcd --- /dev/null +++ b/nxcomp/src/RenderPictureClip.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderPictureClip_H +#define RenderPictureClip_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderPictureClip" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderPictureClipStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 12 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderPictureClip_H */ diff --git a/nxcomp/src/RenderPictureFilter.cpp b/nxcomp/src/RenderPictureFilter.cpp new file mode 100644 index 000000000..ce40e051a --- /dev/null +++ b/nxcomp/src/RenderPictureFilter.cpp @@ -0,0 +1,278 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderPictureFilter.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding value " + << ((size - MESSAGE_OFFSET) >> 2) << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << size + << ".\n" << logofs_flush; + #endif + + size = MESSAGE_OFFSET + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> renderSrcPictureCache); + + encodeBuffer.encodeCachedValue(GetUINT(buffer + 8, bigEndian), 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeXidValue(value, + clientCache -> renderSrcPictureCache); + + PutULONG(value, buffer + 4, bigEndian); + + decodeBuffer.decodeCachedValue(value, 16, + clientCache -> renderLengthCache, 5); + + PutUINT(value, buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + encodeCharData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + decodeCharData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.picture_filter.type = *(buffer + 1); + + renderExtension -> data.picture_filter.src_id = GetULONG(buffer + 4, bigEndian); + renderExtension -> data.picture_filter.num_elm = GetUINT(buffer + 8, bigEndian); + + // + // Clean the padding bytes. This + // should be the purpose of the + // filter. + // + + #ifdef TEST + *logofs << name() << ": Cleaning " + << RoundUp4(renderExtension -> data.picture_filter.num_elm) - + renderExtension -> data.picture_filter.num_elm << " bytes " + << "at offset " << MESSAGE_OFFSET + renderExtension -> + data.picture_filter.num_elm << " with " << renderExtension -> + data.picture_filter.num_elm << " elements and size " + << renderExtension -> size_ << ".\n" << logofs_flush; + #endif + + if (size >= MESSAGE_OFFSET + renderExtension -> + data.picture_filter.num_elm) + { + unsigned char *next = (unsigned char *) buffer + + MESSAGE_OFFSET + renderExtension -> + data.picture_filter.num_elm; + + while (next < buffer + size) + { + *next++ = '\0'; + } + } + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.picture_filter.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.picture_filter.type; + + PutULONG(renderExtension -> data.picture_filter.src_id, buffer + 4, bigEndian); + PutUINT(renderExtension -> data.picture_filter.num_elm, buffer + 8, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.picture_filter.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + // + // Include the length of the filter name + // in the checksum. + // + + md5_append(md5_state, buffer + 1, 3); + md5_append(md5_state, buffer + 8, 2); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(renderExtension -> data.picture_filter.src_id, + clientCache -> renderSrcPictureCache); + + cachedRenderExtension -> data.picture_filter.src_id = + renderExtension -> data.picture_filter.src_id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.picture_filter.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(renderExtension -> data.picture_filter.src_id, + clientCache -> renderSrcPictureCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.picture_filter.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderPictureFilter.h b/nxcomp/src/RenderPictureFilter.h new file mode 100644 index 000000000..a3e37538b --- /dev/null +++ b/nxcomp/src/RenderPictureFilter.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderPictureFilter_H +#define RenderPictureFilter_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderPictureFilter" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderPictureFilterStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 12 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderPictureFilter_H */ diff --git a/nxcomp/src/RenderPictureTransform.cpp b/nxcomp/src/RenderPictureTransform.cpp new file mode 100644 index 000000000..0048e61f4 --- /dev/null +++ b/nxcomp/src/RenderPictureTransform.cpp @@ -0,0 +1,214 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderPictureTransform.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + // + // Size is always 44. The identity size + // is set to 8, so we encode the 36 bytes + // of the transformation matrix as our + // data. + // +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + size = MESSAGE_OFFSET + 36; + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(GetULONG(buffer + 4, bigEndian), + clientCache -> renderSrcPictureCache); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeXidValue(value, + clientCache -> renderSrcPictureCache); + + PutULONG(value, buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.picture_transform.type = *(buffer + 1); + + renderExtension -> data.picture_transform.src_id = GetULONG(buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.picture_transform.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.picture_transform.type; + + PutULONG(renderExtension -> data.picture_transform.src_id, buffer + 4, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.picture_transform.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + md5_append(md5_state, buffer + 1, 3); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(renderExtension -> data.picture_transform.src_id, + clientCache -> renderSrcPictureCache); + + cachedRenderExtension -> data.picture_transform.src_id = + renderExtension -> data.picture_transform.src_id; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.picture_transform.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(renderExtension -> data.picture_transform.src_id, + clientCache -> renderSrcPictureCache); + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.picture_transform.type + << " size is " << renderExtension -> size_ << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderPictureTransform.h b/nxcomp/src/RenderPictureTransform.h new file mode 100644 index 000000000..649cd05d3 --- /dev/null +++ b/nxcomp/src/RenderPictureTransform.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderPictureTransform_H +#define RenderPictureTransform_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderPictureTransform" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderPictureTransformStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 8 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return MESSAGE_OFFSET; + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderPictureTransform_H */ diff --git a/nxcomp/src/RenderTrapezoids.cpp b/nxcomp/src/RenderTrapezoids.cpp new file mode 100644 index 000000000..bf84509dc --- /dev/null +++ b/nxcomp/src/RenderTrapezoids.cpp @@ -0,0 +1,372 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderTrapezoids.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + // + // The trapezoid data is made up of a structure + // containing a top and bottom coordinate in 4 + // bytes format, plus two lines, each represent- + // ed as four points in 4 bytes format. Thus + // each trapezoid is 4 * 2 + (4 * 4) * 2 = 40 + // bytes. Bytes are all padded to an long int, + // so we don't need to clean the message. + // + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding value " + << ((size - MESSAGE_OFFSET) >> 2) << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << size + << ".\n" << logofs_flush; + #endif + + size = MESSAGE_OFFSET + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), + clientCache -> renderSrcPictureCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 12, bigEndian), + clientCache -> renderDstPictureCache); + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 32, + clientCache -> renderFormatCache); + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 20, bigEndian), + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 22, bigEndian), + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + decodeBuffer.decodeXidValue(value, + clientCache -> renderSrcPictureCache); + + PutULONG(value, buffer + 8, bigEndian); + + decodeBuffer.decodeXidValue(value, + clientCache -> renderDstPictureCache); + + PutULONG(value, buffer + 12, bigEndian); + + decodeBuffer.decodeCachedValue(value, 32, + clientCache -> renderFormatCache); + + PutULONG(value, buffer + 16, bigEndian); + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + PutUINT(clientCache -> renderLastX, buffer + 20, bigEndian); + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + PutUINT(clientCache -> renderLastY, buffer + 22, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + if (size > MESSAGE_OFFSET) + { + encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + } + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of text data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + if (size > MESSAGE_OFFSET) + { + decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + } + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.trapezoids.type = *(buffer + 1); + renderExtension -> data.trapezoids.op = *(buffer + 4); + + renderExtension -> data.trapezoids.src_id = GetULONG(buffer + 8, bigEndian); + renderExtension -> data.trapezoids.dst_id = GetULONG(buffer + 12, bigEndian); + + renderExtension -> data.trapezoids.format = GetULONG(buffer + 16, bigEndian); + + renderExtension -> data.trapezoids.src_x = GetUINT(buffer + 20, bigEndian); + renderExtension -> data.trapezoids.src_y = GetUINT(buffer + 22, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.trapezoids.type + << " size is " << renderExtension -> size_ << " identity size " + << renderExtension -> i_size_ << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.trapezoids.type; + *(buffer + 4) = renderExtension -> data.trapezoids.op; + + PutULONG(renderExtension -> data.trapezoids.src_id, buffer + 8, bigEndian); + PutULONG(renderExtension -> data.trapezoids.dst_id, buffer + 12, bigEndian); + + PutULONG(renderExtension -> data.trapezoids.format, buffer + 16, bigEndian); + + PutUINT(renderExtension -> data.trapezoids.src_x, buffer + 20, bigEndian); + PutUINT(renderExtension -> data.trapezoids.src_y, buffer + 22, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.trapezoids.type + << " size is " << renderExtension -> size_ << " identity size " + << renderExtension -> i_size_ << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + // + // Include minor opcode, size and the + // operator in the identity. + // + + md5_append(md5_state, buffer + 1, 4); + + // + // Also include the format but not the + // x and y source. + // + + md5_append(md5_state, buffer + 16, 4); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(renderExtension -> data.trapezoids.src_id, + clientCache -> renderSrcPictureCache); + + cachedRenderExtension -> data.trapezoids.src_id = + renderExtension -> data.trapezoids.src_id; + + encodeBuffer.encodeXidValue(renderExtension -> data.trapezoids.dst_id, + clientCache -> renderDstPictureCache); + + cachedRenderExtension -> data.trapezoids.dst_id = + renderExtension -> data.trapezoids.dst_id; + + // + // The source x and y coordinates are + // encoded as differerences in respect + // to the previous cached value. + // + + unsigned int value; + unsigned int previous; + + value = renderExtension -> data.trapezoids.src_x; + previous = cachedRenderExtension -> data.trapezoids.src_x; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderXCache, 11); + + cachedRenderExtension -> data.trapezoids.src_x = value; + + value = renderExtension -> data.trapezoids.src_y; + previous = cachedRenderExtension -> data.trapezoids.src_y; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderYCache, 11); + + cachedRenderExtension -> data.trapezoids.src_y = value; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.trapezoids.type + << " size is " << renderExtension -> size_ << " source x " + << renderExtension -> data.trapezoids.src_x << " y " + << renderExtension -> data.trapezoids.src_y << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(renderExtension -> data.trapezoids.src_id, + clientCache -> renderSrcPictureCache); + + decodeBuffer.decodeXidValue(renderExtension -> data.trapezoids.dst_id, + clientCache -> renderDstPictureCache); + + unsigned int value; + unsigned int previous; + + previous = renderExtension -> data.trapezoids.src_x; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderXCache, 11); + + renderExtension -> data.trapezoids.src_x = value; + + previous = renderExtension -> data.trapezoids.src_y; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderYCache, 11); + + renderExtension -> data.trapezoids.src_y = value; + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.trapezoids.type + << " size is " << renderExtension -> size_ << " source x " + << renderExtension -> data.trapezoids.src_x << " y " + << renderExtension -> data.trapezoids.src_y << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderTrapezoids.h b/nxcomp/src/RenderTrapezoids.h new file mode 100644 index 000000000..faf524c76 --- /dev/null +++ b/nxcomp/src/RenderTrapezoids.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderTrapezoids_H +#define RenderTrapezoids_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderTrapezoids" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderTrapezoidsStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 24 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return (size >= MESSAGE_OFFSET ? MESSAGE_OFFSET : size); + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderTrapezoids_H */ diff --git a/nxcomp/src/RenderTriangles.cpp b/nxcomp/src/RenderTriangles.cpp new file mode 100644 index 000000000..a5eb4d83d --- /dev/null +++ b/nxcomp/src/RenderTriangles.cpp @@ -0,0 +1,362 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// +// Include the template for +// this message class. +// + +#include "RenderTriangles.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#include MESSAGE_TAGS + +// +// Message handling methods. +// + +MESSAGE_BEGIN_ENCODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding value " + << ((size - MESSAGE_OFFSET) >> 2) << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue((size - MESSAGE_OFFSET) >> 2, 16, + clientCache -> renderLengthCache, 5); + + #ifdef TEST + *logofs << name() << ": Encoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_SIZE + +MESSAGE_BEGIN_DECODE_SIZE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(size, 16, + clientCache -> renderLengthCache, 5); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << size + << ".\n" << logofs_flush; + #endif + + size = MESSAGE_OFFSET + (size << 2); + + buffer = writeBuffer -> addMessage(size); + + #ifdef TEST + *logofs << name() << ": Decoded size with value " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_SIZE + +MESSAGE_BEGIN_ENCODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 8, bigEndian), + clientCache -> renderSrcPictureCache); + + encodeBuffer.encodeXidValue(GetULONG(buffer + 12, bigEndian), + clientCache -> renderDstPictureCache); + + encodeBuffer.encodeCachedValue(GetULONG(buffer + 16, bigEndian), 32, + clientCache -> renderFormatCache); + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 20, bigEndian), + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + encodeBuffer.encodeDiffCachedValue(GetUINT(buffer + 22, bigEndian), + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + #ifdef TEST + *logofs << name() << ": Encoded message. Type is " + << (unsigned int) *(buffer + 1) << " size is " + << size << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_MESSAGE + +MESSAGE_BEGIN_DECODE_MESSAGE +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + *(buffer + 1) = type; + + decodeBuffer.decodeCachedValue(*(buffer + 4), 8, + clientCache -> renderOpCache); + + decodeBuffer.decodeXidValue(value, + clientCache -> renderSrcPictureCache); + + PutULONG(value, buffer + 8, bigEndian); + + decodeBuffer.decodeXidValue(value, + clientCache -> renderDstPictureCache); + + PutULONG(value, buffer + 12, bigEndian); + + decodeBuffer.decodeCachedValue(value, 32, + clientCache -> renderFormatCache); + + PutULONG(value, buffer + 16, bigEndian); + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastX, 16, + clientCache -> renderXCache, 11); + + PutUINT(clientCache -> renderLastX, buffer + 20, bigEndian); + + decodeBuffer.decodeDiffCachedValue(value, + clientCache -> renderLastY, 16, + clientCache -> renderYCache, 11); + + PutUINT(clientCache -> renderLastY, buffer + 22, bigEndian); + + #ifdef TEST + *logofs << name() << ": Decoded message. Type is " + << (unsigned int) type << " size is " << size + << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_MESSAGE + +MESSAGE_BEGIN_ENCODE_DATA +{ + if (size > MESSAGE_OFFSET) + { + encodeLongData(encodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + } + + #ifdef TEST + *logofs << name() << ": Encoded " << size - MESSAGE_OFFSET + << " bytes of text data.\n" << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_DATA + +MESSAGE_BEGIN_DECODE_DATA +{ + if (size > MESSAGE_OFFSET) + { + decodeLongData(decodeBuffer, buffer, MESSAGE_OFFSET, + size, bigEndian, channelCache); + } + + #ifdef TEST + *logofs << name() << ": Decoded " << size - MESSAGE_OFFSET + << " bytes of data.\n" << logofs_flush; + #endif +} +MESSAGE_END_DECODE_DATA + +MESSAGE_BEGIN_PARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + renderExtension -> data.triangles.type = *(buffer + 1); + renderExtension -> data.triangles.op = *(buffer + 4); + + renderExtension -> data.triangles.src_id = GetULONG(buffer + 8, bigEndian); + renderExtension -> data.triangles.dst_id = GetULONG(buffer + 12, bigEndian); + + renderExtension -> data.triangles.format = GetULONG(buffer + 16, bigEndian); + + renderExtension -> data.triangles.src_x = GetUINT(buffer + 20, bigEndian); + renderExtension -> data.triangles.src_y = GetUINT(buffer + 22, bigEndian); + + #ifdef TEST + *logofs << name() << ": Parsed identity. Type is " + << (unsigned int) renderExtension -> data.triangles.type + << " size is " << renderExtension -> size_ << " identity size " + << renderExtension -> i_size_ << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_PARSE_IDENTITY + +MESSAGE_BEGIN_UNPARSE_IDENTITY +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + *(buffer + 1) = renderExtension -> data.triangles.type; + *(buffer + 4) = renderExtension -> data.triangles.op; + + PutULONG(renderExtension -> data.triangles.src_id, buffer + 8, bigEndian); + PutULONG(renderExtension -> data.triangles.dst_id, buffer + 12, bigEndian); + + PutULONG(renderExtension -> data.triangles.format, buffer + 16, bigEndian); + + PutUINT(renderExtension -> data.triangles.src_x, buffer + 20, bigEndian); + PutUINT(renderExtension -> data.triangles.src_y, buffer + 22, bigEndian); + + #ifdef TEST + *logofs << name() << ": Unparsed identity. Type is " + << (unsigned int) renderExtension -> data.triangles.type + << " size is " << renderExtension -> size_ << " identity size " + << renderExtension -> i_size_ << ".\n" << logofs_flush; + #endif +} +MESSAGE_END_UNPARSE_IDENTITY + +MESSAGE_BEGIN_IDENTITY_CHECKSUM +{ + // + // Include minor opcode, size and the + // operator in the identity. + // + + md5_append(md5_state, buffer + 1, 4); + + // + // Also include the format but not the + // x and y source. + // + + md5_append(md5_state, buffer + 16, 4); +} +MESSAGE_END_IDENTITY_CHECKSUM + +MESSAGE_BEGIN_ENCODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + RenderExtensionMessage *cachedRenderExtension = (RenderExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeXidValue(renderExtension -> data.triangles.src_id, + clientCache -> renderSrcPictureCache); + + cachedRenderExtension -> data.triangles.src_id = + renderExtension -> data.triangles.src_id; + + encodeBuffer.encodeXidValue(renderExtension -> data.triangles.dst_id, + clientCache -> renderDstPictureCache); + + cachedRenderExtension -> data.triangles.dst_id = + renderExtension -> data.triangles.dst_id; + + // + // The source x and y coordinates are + // encoded as differerences in respect + // to the previous cached value. + // + + unsigned int value; + unsigned int previous; + + value = renderExtension -> data.triangles.src_x; + previous = cachedRenderExtension -> data.triangles.src_x; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderXCache, 11); + + cachedRenderExtension -> data.triangles.src_x = value; + + value = renderExtension -> data.triangles.src_y; + previous = cachedRenderExtension -> data.triangles.src_y; + + encodeBuffer.encodeDiffCachedValue(value, previous, 16, + clientCache -> renderYCache, 11); + + cachedRenderExtension -> data.triangles.src_y = value; + + #ifdef TEST + *logofs << name() << ": Encoded update. Type is " + << (unsigned int) renderExtension -> data.triangles.type + << " size is " << renderExtension -> size_ << " source x " + << renderExtension -> data.triangles.src_x << " y " + << renderExtension -> data.triangles.src_y << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_ENCODE_UPDATE + +MESSAGE_BEGIN_DECODE_UPDATE +{ + RenderExtensionMessage *renderExtension = (RenderExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeXidValue(renderExtension -> data.triangles.src_id, + clientCache -> renderSrcPictureCache); + + decodeBuffer.decodeXidValue(renderExtension -> data.triangles.dst_id, + clientCache -> renderDstPictureCache); + + unsigned int value; + unsigned int previous; + + previous = renderExtension -> data.triangles.src_x; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderXCache, 11); + + renderExtension -> data.triangles.src_x = value; + + previous = renderExtension -> data.triangles.src_y; + + decodeBuffer.decodeDiffCachedValue(value, previous, 16, + clientCache -> renderYCache, 11); + + renderExtension -> data.triangles.src_y = value; + + #ifdef TEST + *logofs << name() << ": Decoded update. Type is " + << (unsigned int) renderExtension -> data.triangles.type + << " size is " << renderExtension -> size_ << " source x " + << renderExtension -> data.triangles.src_x << " y " + << renderExtension -> data.triangles.src_y << ".\n" + << logofs_flush; + #endif +} +MESSAGE_END_DECODE_UPDATE diff --git a/nxcomp/src/RenderTriangles.h b/nxcomp/src/RenderTriangles.h new file mode 100644 index 000000000..d73efb7b8 --- /dev/null +++ b/nxcomp/src/RenderTriangles.h @@ -0,0 +1,88 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef RenderTriangles_H +#define RenderTriangles_H + +// +// Define the characteristics +// of this message class here. +// + +#undef MESSAGE_NAME +#define MESSAGE_NAME "RenderTriangles" + +#undef MESSAGE_STORE +#define MESSAGE_STORE RenderTrianglesStore + +#undef MESSAGE_CLASS +#define MESSAGE_CLASS RenderMinorExtensionStore + +#undef MESSAGE_METHODS +#define MESSAGE_METHODS "RenderMinorExtensionMethods.h" + +#undef MESSAGE_HEADERS +#define MESSAGE_HEADERS "RenderMinorExtensionHeaders.h" + +#undef MESSAGE_TAGS +#define MESSAGE_TAGS "RenderMinorExtensionTags.h" + +#undef MESSAGE_OFFSET +#define MESSAGE_OFFSET 24 + +#undef MESSAGE_HAS_SIZE +#define MESSAGE_HAS_SIZE 1 + +#undef MESSAGE_HAS_DATA +#define MESSAGE_HAS_DATA 1 + +#undef MESSAGE_HAS_FILTER +#define MESSAGE_HAS_FILTER 0 + +// +// Declare the message class. +// + +#include MESSAGE_HEADERS + +class MESSAGE_STORE : public MESSAGE_CLASS +{ + public: + + virtual const char *name() const + { + return MESSAGE_NAME; + } + + virtual int identitySize(const unsigned char *buffer, + unsigned int size) + { + return (size >= MESSAGE_OFFSET ? MESSAGE_OFFSET : size); + } + + #include MESSAGE_METHODS +}; + +#endif /* RenderTriangles_H */ diff --git a/nxcomp/src/Rgb.cpp b/nxcomp/src/Rgb.cpp new file mode 100644 index 000000000..c98fa5147 --- /dev/null +++ b/nxcomp/src/Rgb.cpp @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "Rgb.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int UnpackRgb(T_geometry *geometry, unsigned char method, unsigned char *src_data, + int src_size, int dst_bpp, int dst_width, int dst_height, + unsigned char *dst_data, int dst_size) +{ + if (*src_data == 0) + { + if (dst_size != src_size - 1) + { + #ifdef TEST + *logofs << "UnpackRgb: PANIC! Invalid destination size " + << dst_size << " with source " << src_size + << ".\n" << logofs_flush; + #endif + + return -1; + } + + #ifdef TEST + *logofs << "UnpackRgb: Expanding " << src_size - 1 + << " bytes of plain RGB data.\n" << logofs_flush; + #endif + + memcpy(dst_data, src_data + 1, src_size - 1); + + return 1; + } + + unsigned int check_size = dst_size; + + int result = ZDecompress(&unpackStream, dst_data, &check_size, + src_data + 1, src_size - 1); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "UnpackRgb: PANIC! Failure decompressing RGB data. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decompressing RGB data. " + << "Error is '" << zError(result) << "'.\n"; + + return -1; + } + else if (check_size != (unsigned int) dst_size) + { + #ifdef PANIC + *logofs << "UnpackRgb: PANIC! Size mismatch in RGB data. " + << "Resulting size is " << check_size << " with " + << "expected size " << dst_size << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Size mismatch in RGB data. " + << "Resulting size is " << check_size << " with " + << "expected size " << dst_size << ".\n"; + + return -1; + } + + #ifdef TEST + *logofs << "UnpackRgb: Decompressed " << src_size - 1 + << " bytes to " << dst_size << " bytes of RGB data.\n" + << logofs_flush; + #endif + + return 1; +} diff --git a/nxcomp/src/Rgb.h b/nxcomp/src/Rgb.h new file mode 100644 index 000000000..ec088dd1b --- /dev/null +++ b/nxcomp/src/Rgb.h @@ -0,0 +1,36 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Rgb_H +#define Rgb_H + +#include "Unpack.h" + +int UnpackRgb(T_geometry *geometry, unsigned char method, + unsigned char *src_data, int src_size, int dst_bpp, + int dst_width, int dst_height, unsigned char *dst_data, + int dst_size); + +#endif /* Rgb_H */ diff --git a/nxcomp/src/Rle.cpp b/nxcomp/src/Rle.cpp new file mode 100644 index 000000000..2a145aa0c --- /dev/null +++ b/nxcomp/src/Rle.cpp @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "Rle.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int UnpackRle(T_geometry *geometry, unsigned char method, unsigned char *src_data, + int src_size, int dst_bpp, int dst_width, int dst_height, + unsigned char *dst_data, int dst_size) +{ + if (*src_data == 0) + { + if (dst_size != src_size - 1) + { + #ifdef TEST + *logofs << "UnpackRle: PANIC! Invalid destination size " + << dst_size << " with source " << src_size + << ".\n" << logofs_flush; + #endif + + return -1; + } + + #ifdef TEST + *logofs << "UnpackRle: Expanding " << src_size - 1 + << " bytes of plain RLE data.\n" << logofs_flush; + #endif + + memcpy(dst_data, src_data + 1, src_size - 1); + + return 1; + } + + unsigned int check_size = dst_size; + + int result = ZDecompress(&unpackStream, dst_data, &check_size, + src_data + 1, src_size - 1); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "UnpackRle: PANIC! Failure decompressing RLE data. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decompressing RLE data. " + << "Error is '" << zError(result) << "'.\n"; + + return -1; + } + else if (check_size != (unsigned int) dst_size) + { + #ifdef PANIC + *logofs << "UnpackRle: PANIC! Size mismatch in RLE data. " + << "Resulting size is " << check_size << " with " + << "expected size " << dst_size << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Size mismatch in RLE data. " + << "Resulting size is " << check_size << " with " + << "expected size " << dst_size << ".\n"; + + return -1; + } + + #ifdef TEST + *logofs << "UnpackRle: Decompressed " << src_size - 1 + << " bytes to " << dst_size << " bytes of RLE data.\n" + << logofs_flush; + #endif + + return 1; +} diff --git a/nxcomp/src/Rle.h b/nxcomp/src/Rle.h new file mode 100644 index 000000000..cc5dab0e8 --- /dev/null +++ b/nxcomp/src/Rle.h @@ -0,0 +1,36 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Rle_H +#define Rle_H + +#include "Unpack.h" + +int UnpackRle(T_geometry *geometry, unsigned char method, + unsigned char *src_data, int src_size, int dst_bpp, + int dst_width, int dst_height, unsigned char *dst_data, + int dst_size); + +#endif /* Rle_H */ diff --git a/nxcomp/src/SendEvent.cpp b/nxcomp/src/SendEvent.cpp new file mode 100644 index 000000000..8867d0a9e --- /dev/null +++ b/nxcomp/src/SendEvent.cpp @@ -0,0 +1,304 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SendEvent.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "IntCache.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int SendEventStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SendEventMessage *sendEvent = (SendEventMessage *) message; + + // + // Here is the fingerprint. + // + + sendEvent -> propagate = *(buffer + 1); + + sendEvent -> window = GetULONG(buffer + 4, bigEndian); + sendEvent -> mask = GetULONG(buffer + 8, bigEndian); + + sendEvent -> code = *(buffer + 12); + sendEvent -> byte_data = *(buffer + 13); + + sendEvent -> sequence = GetUINT(buffer + 14, bigEndian); + + sendEvent -> int_data = GetULONG(buffer + 16, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int SendEventStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SendEventMessage *sendEvent = (SendEventMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = sendEvent -> propagate; + + PutULONG(sendEvent -> window, buffer + 4, bigEndian); + PutULONG(sendEvent -> mask, buffer + 8, bigEndian); + + *(buffer + 12) = sendEvent -> code; + *(buffer + 13) = sendEvent -> byte_data; + + PutUINT(sendEvent -> sequence, buffer + 14, bigEndian); + + PutULONG(sendEvent -> int_data, buffer + 16, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void SendEventStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + SendEventMessage *sendEvent = (SendEventMessage *) message; + + *logofs << name() << ": Identity propagate " << (unsigned int) sendEvent -> propagate + << ", window " << sendEvent -> window << ", mask " << sendEvent -> mask + << ", code " << (unsigned int) sendEvent -> code << ", byte_data " + << (unsigned int) sendEvent -> byte_data << ", sequence " + << sendEvent -> sequence << ", int_data " << sendEvent -> int_data + << ", size " << sendEvent -> size_ << ".\n" << logofs_flush; + + #endif +} + +void SendEventStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ +} + +void SendEventStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + SendEventMessage *sendEvent = (SendEventMessage *) message; + SendEventMessage *cachedSendEvent = (SendEventMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << (unsigned int) sendEvent -> propagate + << " as propagate field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeBoolValue(sendEvent -> propagate); + + cachedSendEvent -> propagate = sendEvent -> propagate; + + #ifdef TEST + *logofs << name() << ": Encoding value " << sendEvent -> window + << " as window field.\n" << logofs_flush; + #endif + + if (sendEvent -> window == 0 || sendEvent -> window == 1) + { + encodeBuffer.encodeBoolValue(1); + + encodeBuffer.encodeBoolValue(sendEvent -> window); + } + else + { + encodeBuffer.encodeBoolValue(0); + + encodeBuffer.encodeXidValue(sendEvent -> window, clientCache -> windowCache); + } + + cachedSendEvent -> window = sendEvent -> window; + + #ifdef TEST + *logofs << name() << ": Encoding value " << sendEvent -> mask + << " as mask field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(sendEvent -> mask, 32, + clientCache -> sendEventMaskCache); + + cachedSendEvent -> mask = sendEvent -> mask; + + #ifdef TEST + *logofs << name() << ": Encoding value " << sendEvent -> code + << " as code field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(sendEvent -> code, 8, + clientCache -> sendEventCodeCache); + + cachedSendEvent -> code = sendEvent -> code; + + #ifdef TEST + *logofs << name() << ": Encoding value " << sendEvent -> byte_data + << " as byte_data field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(sendEvent -> byte_data, 8, + clientCache -> sendEventByteDataCache); + + cachedSendEvent -> byte_data = sendEvent -> byte_data; + + #ifdef TEST + *logofs << name() << ": Encoding value " << sendEvent -> sequence + << " as sequence field.\n" << logofs_flush; + #endif + + unsigned int diffSeq = sendEvent -> sequence - + clientCache -> sendEventLastSequence; + + clientCache -> sendEventLastSequence = sendEvent -> sequence; + + encodeBuffer.encodeValue(diffSeq, 16, 4); + + cachedSendEvent -> sequence = sendEvent -> sequence; + + #ifdef TEST + *logofs << name() << ": Encoding value " << sendEvent -> int_data + << " as int_data field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(sendEvent -> int_data, 32, + clientCache -> sendEventIntDataCache); + + cachedSendEvent -> int_data = sendEvent -> int_data; +} + +void SendEventStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + SendEventMessage *sendEvent = (SendEventMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeBoolValue(value); + + sendEvent -> propagate = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << (unsigned int) sendEvent -> propagate + << " as propagate field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeBoolValue(value); + + if (value) + { + decodeBuffer.decodeBoolValue(value); + } + else + { + decodeBuffer.decodeXidValue(value, clientCache -> windowCache); + } + + sendEvent -> window = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << sendEvent -> window + << " as window field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(sendEvent -> mask, 32, + clientCache -> sendEventMaskCache); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << sendEvent -> mask + << " as mask field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(sendEvent -> code, 8, + clientCache -> sendEventCodeCache); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << sendEvent -> code + << " as code field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(sendEvent -> byte_data, 8, + clientCache -> sendEventByteDataCache); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << sendEvent -> byte_data + << " as byte_data field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeValue(value, 16, 4); + + clientCache -> sendEventLastSequence += value; + clientCache -> sendEventLastSequence &= 0xffff; + + sendEvent -> sequence = clientCache -> sendEventLastSequence; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << sendEvent -> sequence + << " as sequence field.\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(sendEvent -> int_data, 32, + clientCache -> sendEventIntDataCache); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << sendEvent -> int_data + << " as int_data field.\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/SendEvent.h b/nxcomp/src/SendEvent.h new file mode 100644 index 000000000..a8841a706 --- /dev/null +++ b/nxcomp/src/SendEvent.h @@ -0,0 +1,195 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef SendEvent_H +#define SendEvent_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define SENDEVENT_ENABLE_CACHE 1 +#define SENDEVENT_ENABLE_DATA 0 +#define SENDEVENT_ENABLE_SPLIT 0 +#define SENDEVENT_ENABLE_COMPRESS 0 + +#define SENDEVENT_DATA_LIMIT 24 +#define SENDEVENT_DATA_OFFSET 20 + +#define SENDEVENT_CACHE_SLOTS 2000 +#define SENDEVENT_CACHE_THRESHOLD 2 +#define SENDEVENT_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class SendEventMessage : public Message +{ + friend class SendEventStore; + + public: + + SendEventMessage() + { + } + + ~SendEventMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char propagate; + unsigned int window; + unsigned int mask; + + // + // These are part of the event data. + // + + unsigned char code; + unsigned char byte_data; + unsigned short sequence; + unsigned int int_data; +}; + +class SendEventStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + SendEventStore() : MessageStore() + { + enableCache = SENDEVENT_ENABLE_CACHE; + enableData = SENDEVENT_ENABLE_DATA; + enableSplit = SENDEVENT_ENABLE_SPLIT; + enableCompress = SENDEVENT_ENABLE_COMPRESS; + + dataLimit = SENDEVENT_DATA_LIMIT; + dataOffset = SENDEVENT_DATA_OFFSET; + + cacheSlots = SENDEVENT_CACHE_SLOTS; + cacheThreshold = SENDEVENT_CACHE_THRESHOLD; + cacheLowerThreshold = SENDEVENT_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~SendEventStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "SendEvent"; + } + + virtual unsigned char opcode() const + { + return X_SendEvent; + } + + virtual unsigned int storage() const + { + return sizeof(SendEventMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new SendEventMessage(); + } + + virtual Message *create(const Message &message) const + { + return new SendEventMessage((const SendEventMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (SendEventMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* SendEvent_H */ diff --git a/nxcomp/src/SequenceQueue.cpp b/nxcomp/src/SequenceQueue.cpp new file mode 100644 index 000000000..a045875d7 --- /dev/null +++ b/nxcomp/src/SequenceQueue.cpp @@ -0,0 +1,174 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SequenceQueue.h" + +static const unsigned int INITIAL_SIZE_ = 16; +static const unsigned int GROWTH_INCREMENT = 16; + +SequenceQueue::SequenceQueue() + + : queue_(new RequestSequence[INITIAL_SIZE_]), size_(INITIAL_SIZE_), + length_(0), start_(0), end_(0) +{ +} + +SequenceQueue::~SequenceQueue() +{ + delete [] queue_; +} + +void SequenceQueue::push(unsigned short int sequence, unsigned char opcode, + unsigned int data1, unsigned int data2, + unsigned int data3) +{ + if (length_ == 0) + { + start_ = end_ = 0; + + queue_[0].opcode = opcode; + queue_[0].sequence = sequence; + + queue_[0].data1 = data1; + queue_[0].data2 = data2; + queue_[0].data3 = data3; + + length_ = 1; + + return; + } + + if (length_ == size_) + { + size_ += GROWTH_INCREMENT; + + RequestSequence *newQueue = new RequestSequence[size_]; + + for (int i = start_; (unsigned int) i < length_; i++) + { + newQueue[i - start_] = queue_[i]; + } + + for (int i1 = 0; (unsigned int) i1 < start_; i1++) + { + newQueue[i1 + length_ - start_] = queue_[i1]; + } + + delete [] queue_; + + queue_ = newQueue; + + start_ = 0; + + end_ = length_ - 1; + } + + end_++; + + if (end_ == size_) + { + end_ = 0; + } + + queue_[end_].opcode = opcode; + queue_[end_].sequence = sequence; + + queue_[end_].data1 = data1; + queue_[end_].data2 = data2; + queue_[end_].data3 = data3; + + length_++; +} + +int SequenceQueue::peek(unsigned short int &sequence, + unsigned char &opcode) +{ + if (length_ == 0) + { + return 0; + } + else + { + opcode = queue_[start_].opcode; + sequence = queue_[start_].sequence; + + return 1; + } +} + +int SequenceQueue::peek(unsigned short int &sequence, unsigned char &opcode, + unsigned int &data1, unsigned int &data2, + unsigned int &data3) +{ + if (length_ == 0) + { + return 0; + } + else + { + opcode = queue_[start_].opcode; + sequence = queue_[start_].sequence; + + data1 = queue_[start_].data1; + data2 = queue_[start_].data2; + data3 = queue_[start_].data3; + + return 1; + } +} + +int SequenceQueue::pop(unsigned short int &sequence, unsigned char &opcode, + unsigned int &data1, unsigned int &data2, + unsigned int &data3) +{ + if (length_ == 0) + { + return 0; + } + else + { + opcode = queue_[start_].opcode; + sequence = queue_[start_].sequence; + + data1 = queue_[start_].data1; + data2 = queue_[start_].data2; + data3 = queue_[start_].data3; + + start_++; + + if (start_ == size_) + { + start_ = 0; + } + + length_--; + + return 1; + } +} diff --git a/nxcomp/src/SequenceQueue.h b/nxcomp/src/SequenceQueue.h new file mode 100644 index 000000000..2a72bc3fe --- /dev/null +++ b/nxcomp/src/SequenceQueue.h @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef SequenceQueue_H +#define SequenceQueue_H + +// +// List of outstanding request messages which +// are waiting for a reply. This class is used +// in X client and server channels to correlate +// the replies sequence numbers to the original +// request type. +// + +class SequenceQueue +{ + public: + + SequenceQueue(); + + virtual ~SequenceQueue(); + + void push(unsigned short int sequence, unsigned char opcode, + unsigned int data1 = 0, unsigned int data2 = 0, + unsigned int data3 = 0); + + int peek(unsigned short int &sequence, unsigned char &opcode); + + int peek(unsigned short int &sequence, unsigned char &opcode, + unsigned int &data1, unsigned int &data2, + unsigned int &data3); + + int pop(unsigned short int &sequence, unsigned char &opcode, + unsigned int &data1, unsigned int &data2, + unsigned int &data3); + + int pop(unsigned short int &sequence, unsigned char &opcode) + { + unsigned int data1, data2, data3; + + return pop(sequence, opcode, data1, data2, data3); + } + + int length() + { + return length_; + } + + private: + + struct RequestSequence + { + unsigned short int sequence; + unsigned char opcode; + unsigned int data1; + unsigned int data2; + unsigned int data3; + }; + + RequestSequence *queue_; + + unsigned int size_; + unsigned int length_; + + unsigned int start_; + unsigned int end_; +}; + +#endif /* SequenceQueue_H */ diff --git a/nxcomp/src/ServerCache.cpp b/nxcomp/src/ServerCache.cpp new file mode 100644 index 000000000..c4c088dca --- /dev/null +++ b/nxcomp/src/ServerCache.cpp @@ -0,0 +1,195 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ServerCache.h" + +// +// Some global caches used to store information +// common to all X connections. +// + +BlockCache ServerCache::lastInitReply; +BlockCache ServerCache::lastKeymap; +unsigned char ServerCache::getKeyboardMappingLastKeysymsPerKeycode = 0; +BlockCache ServerCache::getKeyboardMappingLastMap; +BlockCache ServerCache::getModifierMappingLastMap; +BlockCache ServerCache::xResources; +BlockCacheSet ServerCache::queryFontFontCache(16); + +ServerCache::ServerCache() : + + replySequenceCache(6), eventSequenceCache(6), + lastTimestamp(0), visualCache(8), colormapCache(8), + + errorMinorCache(8), + + colormapNotifyWindowCache(8), colormapNotifyColormapCache(8), + + createNotifyWindowCache(8), createNotifyLastWindow(0), + + exposeWindowCache(12), + + focusInWindowCache(8), + + keyPressLastKey(0), + + mapNotifyEventCache(8), mapNotifyWindowCache(8), + + motionNotifyTimestampCache(8), motionNotifyLastRootX(0), + motionNotifyLastRootY(0), motionNotifyRootXCache(8), + motionNotifyRootYCache(8), motionNotifyEventXCache(8), + motionNotifyEventYCache(8), motionNotifyStateCache(8), + + noExposeDrawableCache(8), noExposeMinorCache(8), + + propertyNotifyWindowCache(8), propertyNotifyAtomCache(8), + + reparentNotifyWindowCache(8), + + selectionClearWindowCache(8), selectionClearAtomCache(8), + + visibilityNotifyWindowCache(8), + + getGeometryRootCache(8), + + getInputFocusWindowCache(8), + + getKeyboardMappingKeysymCache(8), + + getPropertyTypeCache(8), + + getSelectionOwnerCache(8), + + getWindowAttributesClassCache(8), getWindowAttributesPlanesCache(8), + getWindowAttributesPixelCache(8), getWindowAttributesAllEventsCache(8), + getWindowAttributesYourEventsCache(8), + getWindowAttributesDontPropagateCache(8), + + queryPointerRootCache(8), queryPointerChildCache(8), + + translateCoordsChildCache(8), translateCoordsXCache(8), + translateCoordsYCache(8), + + queryTreeWindowCache(8) + +{ + unsigned int i; + + for (i = 0; i < 3; i++) + { + configureNotifyWindowCache[i] = new IntCache(8); + } + + for (i = 0; i < 5; i++) + { + configureNotifyGeomCache[i] = new IntCache(8); + } + + for (i = 0; i < 5; i++) + { + exposeGeomCache[i] = new IntCache(8); + } + + for (i = 0; i < 3; i++) + { + motionNotifyWindowCache[i] = new IntCache(8); + } + + for (i = 0; i < 5; i++) + { + getGeometryGeomCache[i] = new IntCache(8); + } + + for (i = 0; i < 23; i++) + { + keyPressCache[i] = 0; + } + + for (i = 0; i < 6; i++) + { + queryFontCharInfoCache[i] = new IntCache(8); + queryFontLastCharInfo[i] = 0; + } + + for (i = 0; i < 12; i++) + { + genericReplyIntCache[i] = new IntCache(8); + } + + for (i = 0; i < 14; i++) + { + genericEventIntCache[i] = new IntCache(8); + } +} + + +ServerCache::~ServerCache() +{ + unsigned int i; + + for (i = 0; i < 3; i++) + { + delete configureNotifyWindowCache[i]; + } + + for (i = 0; i < 5; i++) + { + delete configureNotifyGeomCache[i]; + } + + for (i = 0; i < 5; i++) + { + delete exposeGeomCache[i]; + } + + for (i = 0; i < 3; i++) + { + delete motionNotifyWindowCache[i]; + } + + for (i = 0; i < 5; i++) + { + delete getGeometryGeomCache[i]; + } + + for (i = 0; i < 6; i++) + { + delete queryFontCharInfoCache[i]; + } + + for (i = 0; i < 12; i++) + { + delete genericReplyIntCache[i]; + } + + for (i = 0; i < 14; i++) + { + delete genericEventIntCache[i]; + } +} diff --git a/nxcomp/src/ServerCache.h b/nxcomp/src/ServerCache.h new file mode 100644 index 000000000..c6e2b81b6 --- /dev/null +++ b/nxcomp/src/ServerCache.h @@ -0,0 +1,303 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ServerCache_H +#define ServerCache_H + +#include "Misc.h" + +#include "IntCache.h" +#include "CharCache.h" +#include "OpcodeCache.h" +#include "BlockCache.h" +#include "BlockCacheSet.h" + +#include "ChannelCache.h" + +class ServerCache : public ChannelCache +{ + public: + + ServerCache(); + + ~ServerCache(); + + // + // Opcode prediction caches. + // + + OpcodeCache opcodeCache; + + // + // General-purpose caches. + // + + IntCache replySequenceCache; + IntCache eventSequenceCache; + unsigned int lastTimestamp; + CharCache depthCache; + IntCache visualCache; + IntCache colormapCache; + CharCache resourceCache; + + // + // X connection startup. + // + + static BlockCache lastInitReply; + + // + // X errors. + // + + CharCache errorCodeCache; + IntCache errorMinorCache; + CharCache errorMajorCache; + + // + // ButtonPress and ButtonRelease events. + // + + CharCache buttonCache; + + // + // ColormapNotify event. + // + + IntCache colormapNotifyWindowCache; + IntCache colormapNotifyColormapCache; + + // + // ConfigureNotify event. + // + + IntCache *configureNotifyWindowCache[3]; + IntCache *configureNotifyGeomCache[5]; + + // + // CreateNotify event. + // + + IntCache createNotifyWindowCache; + unsigned int createNotifyLastWindow; + + // + // Expose event. + // + + IntCache exposeWindowCache; + IntCache *exposeGeomCache[5]; + + // + // FocusIn event (also used for FocusOut). + // + + IntCache focusInWindowCache; + + // + // KeymapNotify event. + // + + static BlockCache lastKeymap; + + // + // KeyPress event. + // + + unsigned char keyPressLastKey; + unsigned char keyPressCache[23]; + + // + // MapNotify event (also used for UnmapNotify). + // + + IntCache mapNotifyEventCache; + IntCache mapNotifyWindowCache; + + // + // MotionNotify event (also used for KeyPress, + // KeyRelease, ButtonPress, ButtonRelease, + // EnterNotify, and LeaveNotify events and + // QueryPointer reply). + // + + IntCache motionNotifyTimestampCache; + unsigned int motionNotifyLastRootX; + unsigned int motionNotifyLastRootY; + IntCache motionNotifyRootXCache; + IntCache motionNotifyRootYCache; + IntCache motionNotifyEventXCache; + IntCache motionNotifyEventYCache; + IntCache motionNotifyStateCache; + IntCache *motionNotifyWindowCache[3]; + + // + // NoExpose event. + // + + IntCache noExposeDrawableCache; + IntCache noExposeMinorCache; + CharCache noExposeMajorCache; + + // + // PropertyNotify event. + // + + IntCache propertyNotifyWindowCache; + IntCache propertyNotifyAtomCache; + + // + // ReparentNotify event. + // + + IntCache reparentNotifyWindowCache; + + // + // SelectionClear event. + // + + IntCache selectionClearWindowCache; + IntCache selectionClearAtomCache; + + // + // VisibilityNotify event. + // + + IntCache visibilityNotifyWindowCache; + + // + // GetGeometry reply. + // + + IntCache getGeometryRootCache; + IntCache *getGeometryGeomCache[5]; + + // + // GetInputFocus reply. + // + + IntCache getInputFocusWindowCache; + + // + // GetKeyboardMapping reply. + // + + static unsigned char getKeyboardMappingLastKeysymsPerKeycode; + static BlockCache getKeyboardMappingLastMap; + IntCache getKeyboardMappingKeysymCache; + CharCache getKeyboardMappingLastByteCache; + + // + // GetModifierMapping reply. + // + + static BlockCache getModifierMappingLastMap; + + // + // GetProperty reply. + // + + CharCache getPropertyFormatCache; + IntCache getPropertyTypeCache; + static BlockCache xResources; + + // + // GetSelection reply. + // + + IntCache getSelectionOwnerCache; + + // + // GetWindowAttributes reply. + // + + IntCache getWindowAttributesClassCache; + CharCache getWindowAttributesBitGravityCache; + CharCache getWindowAttributesWinGravityCache; + IntCache getWindowAttributesPlanesCache; + IntCache getWindowAttributesPixelCache; + IntCache getWindowAttributesAllEventsCache; + IntCache getWindowAttributesYourEventsCache; + IntCache getWindowAttributesDontPropagateCache; + + // + // QueryColors reply. + // + + BlockCache queryColorsLastReply; + + // + // QueryFont reply. + // + + static BlockCacheSet queryFontFontCache; + IntCache *queryFontCharInfoCache[6]; + unsigned int queryFontLastCharInfo[6]; + + // + // QueryPointer reply. + // + + IntCache queryPointerRootCache; + IntCache queryPointerChildCache; + + // + // TranslateCoords reply. + // + + IntCache translateCoordsChildCache; + IntCache translateCoordsXCache; + IntCache translateCoordsYCache; + + // + // QueryTree reply. + // + + IntCache queryTreeWindowCache; + + // + // Generic reply. Use short data + // in protocol versions >= 3. + // + + CharCache genericReplyCharCache; + IntCache *genericReplyIntCache[12]; + + // + // Generic event. Only in protocol + // versions >= 3. + // + + CharCache genericEventCharCache; + IntCache *genericEventIntCache[14]; + + // + // Used in the abort split events. + // + + OpcodeCache abortOpcodeCache; +}; + +#endif /* ServerCache_H */ diff --git a/nxcomp/src/ServerChannel.cpp b/nxcomp/src/ServerChannel.cpp new file mode 100644 index 000000000..a560eca6d --- /dev/null +++ b/nxcomp/src/ServerChannel.cpp @@ -0,0 +1,7946 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifndef ANDROID +#include +#endif + +#include +#include + +#include "NXproto.h" +#include "NXalert.h" +#include "NXpack.h" +#include "NXmitshm.h" + +#include "ServerChannel.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "StaticCompressor.h" + +#include "Statistics.h" +#include "Proxy.h" + +#include "Auth.h" +#include "Unpack.h" + +// +// Available unpack methods. +// + +#include "Alpha.h" +#include "Colormap.h" +#include "Bitmap.h" +#include "Jpeg.h" +#include "Pgn.h" +#include "Rgb.h" +#include "Rle.h" + +extern Proxy *proxy; + +// +// Set the verbosity level. You also +// need to define OPCODES in Misc.cpp +// if you want literals instead of +// opcodes' numbers. +// + +#define PANIC +#define WARNING +#undef OPCODES +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Log the important tracepoints related +// to writing packets to the peer proxy. +// + +#undef FLUSH + +// +// Log the operations related to splits. +// + +#undef SPLIT + +// +// Define this to log when a channel +// is created or destroyed. +// + +#undef REFERENCES + +// +// Define this to exit and suspend the +// session after a given number of X +// messages decoded by the proxy. +// + +#undef SUSPEND + +// +// Define these to hide the server extensions. +// + +#define HIDE_MIT_SHM_EXTENSION +#define HIDE_BIG_REQUESTS_EXTENSION +#define HIDE_XFree86_Bigfont_EXTENSION +#undef HIDE_SHAPE_EXTENSION +#undef HIDE_XKEYBOARD_EXTENSION + +// +// Known reasons of connection failures. +// + +#define INVALID_COOKIE_DATA "Invalid MIT-MAGIC-COOKIE-1 key" +#define INVALID_COOKIE_SIZE ((int) sizeof(INVALID_COOKIE_DATA) - 1) + +#define NO_AUTH_PROTO_DATA "No protocol specified" +#define NO_AUTH_PROTO_SIZE ((int) sizeof(NO_AUTH_PROTO_DATA) - 1) + +// +// Here are the static members. +// + +#ifdef REFERENCES + +int ServerChannel::references_ = 0; + +#endif + +ServerChannel::ServerChannel(Transport *transport, StaticCompressor *compressor) + + : Channel(transport, compressor), readBuffer_(transport_, this) +{ + // + // Sequence number of the next message + // being encoded or decoded. + // + + clientSequence_ = 0; + serverSequence_ = 0; + + // + // Save the last motion event and flush + // it only when the timeout expires. + // + + lastMotion_[0] = '\0'; + + // + // Clear the queue of sequence numbers + // of split commits. Used to mask the + // errors. + // + + initCommitQueue(); + + // + // Do we enable or not sending of expose + // events to the X client. + // + + enableExpose_ = 1; + enableGraphicsExpose_ = 1; + enableNoExpose_ = 1; + + // + // Track data of image currently being + // decompressed. + // + + imageState_ = NULL; + + // + // Track MIT-SHM resources. + // + + shmemState_ = NULL; + + // + // Store the unpack state for each agent + // resource. + // + + for (int i = 0; i < CONNECTIONS_LIMIT; i++) + { + unpackState_[i] = NULL; + } + + // + // Data about the split parameters requested + // by the encoding side. + // + + splitState_.resource = nothing; + splitState_.current = 0; + splitState_.save = 1; + splitState_.load = 1; + splitState_.commit = 0; + + // + // It will be eventually set by + // the server proxy. + // + + fontPort_ = -1; + + #ifdef REFERENCES + *logofs << "ServerChannel: Created new object at " + << this << " for FD#" << fd_ << " out of " + << ++references_ << " allocated channels.\n" + << logofs_flush; + #endif +} + +ServerChannel::~ServerChannel() +{ + #ifdef TEST + *logofs << "ServerChannel: Freeing image state information.\n" + << logofs_flush; + #endif + + handleImageStateRemove(); + + #ifdef TEST + *logofs << "ServerChannel: Freeing shared memory information.\n" + << logofs_flush; + #endif + + handleShmemStateRemove(); + + #ifdef TEST + *logofs << "ServerChannel: Freeing unpack state information.\n" + << logofs_flush; + #endif + + for (int i = 0; i < CONNECTIONS_LIMIT; i++) + { + handleUnpackStateRemove(i); + } + + #ifdef TEST + *logofs << "ServerChannel: Freeing channel caches.\n" + << logofs_flush; + #endif + + #ifdef REFERENCES + *logofs << "ServerChannel: Deleted object at " + << this << " for FD#" << fd_ << " out of " + << --references_ << " allocated channels.\n" + << logofs_flush; + #endif +} + +// +// Beginning of handleRead(). +// + +int ServerChannel::handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, + unsigned int length) +{ + #ifdef DEBUG + *logofs << "handleRead: Called for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + // + // Pointer to located message and + // its size in bytes. + // + + const unsigned char *inputMessage; + unsigned int inputLength; + + // + // Set when message is found in + // cache. + // + + int hit; + + #if defined(TEST) || defined(INFO) + *logofs << "handleRead: Trying to read from FD#" + << fd_ << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + int result = readBuffer_.readMessage(); + + #if defined(DEBUG) || defined(INFO) + *logofs << "handleRead: Read result on FD#" << fd_ + << " is " << result << ".\n" + << logofs_flush; + #endif + + if (result < 0) + { + // + // Let the proxy close the channel. + // + + return -1; + } + else if (result == 0) + { + #if defined(TEST) || defined(INFO) + + // + // This can happen because we have the descriptor + // selected in the read set but we already read + // the data asynchronously, while decoding data + // read from the proxy. + // + + *logofs << "handleRead: WARNING! No data read from FD#" + << fd_ << " while encoding messages.\n" + << logofs_flush; + + #endif + + return 0; + } + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "handleRead: Encoding messages for FD#" << fd_ + << " with " << readBuffer_.getLength() << " bytes " + << "in the buffer.\n" << logofs_flush; + #endif + + // + // Extract any complete message which + // is available in the buffer. + // + + if (proxy -> handleAsyncSwitch(fd_) < 0) + { + return -1; + } + + while ((inputMessage = readBuffer_.getMessage(inputLength)) != NULL) + { + hit = 0; + + if (firstReply_) + { + // + // Handle the X server's authorization reply. + // + + if (handleAuthorization(inputMessage, inputLength) < 0) + { + return -1; + } + + imageByteOrder_ = inputMessage[30]; + bitmapBitOrder_ = inputMessage[31]; + scanlineUnit_ = inputMessage[32]; + scanlinePad_ = inputMessage[33]; + + encodeBuffer.encodeValue((unsigned int) inputMessage[0], 8); + encodeBuffer.encodeValue((unsigned int) inputMessage[1], 8); + encodeBuffer.encodeValue(GetUINT(inputMessage + 2, bigEndian_), 16); + encodeBuffer.encodeValue(GetUINT(inputMessage + 4, bigEndian_), 16); + encodeBuffer.encodeValue(GetUINT(inputMessage + 6, bigEndian_), 16); + + if (ServerCache::lastInitReply.compare(inputLength - 8, inputMessage + 8)) + { + encodeBuffer.encodeBoolValue(1); + } + else + { + encodeBuffer.encodeBoolValue(0); + + for (unsigned int i = 8; i < inputLength; i++) + { + encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8); + } + } + + firstReply_ = 0; + + #if defined(TEST) || defined(OPCODES) + + int bits = encodeBuffer.diffBits(); + + *logofs << "handleRead: Handled first reply. " << inputLength + << " bytes in, " << bits << " bits (" << ((float) bits) / 8 + << " bytes) out.\n" << logofs_flush; + + #endif + + priority_++; + + } + else + { + // + // NX client needs this line to consider + // the initialization phase successfully + // completed. + // + + if (firstClient_ == -1) + { + cerr << "Info" << ": Established X server connection.\n" ; + + firstClient_ = fd_; + } + + // + // Check if this is a reply. + // + + if (*inputMessage == X_Reply) + { + int bits = 0; + + unsigned char inputOpcode = *inputMessage; + + unsigned short int requestSequenceNum; + unsigned char requestOpcode; + unsigned int requestData[3]; + + unsigned int sequenceNum = GetUINT(inputMessage + 2, bigEndian_); + + #ifdef SUSPEND + + if (sequenceNum >= 1000) + { + cerr << "Warning" << ": Exiting to test the resilience of the agent.\n"; + + sleep(2); + + HandleAbort(); + } + + #endif + + // + // We managed all the events and errors caused + // by the previous requests. We can now reset + // the queue of split commits. + // + + clearCommitQueue(); + + // + // Encode opcode and difference between + // current sequence and the last one. + // + + encodeBuffer.encodeOpcodeValue(inputOpcode, serverCache_ -> opcodeCache); + + unsigned int sequenceDiff = sequenceNum - serverSequence_; + + serverSequence_ = sequenceNum; + + #ifdef DEBUG + *logofs << "handleRead: Last server sequence number for FD#" + << fd_ << " is " << serverSequence_ << " with " + << "difference " << sequenceDiff << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(sequenceDiff, 16, + serverCache_ -> replySequenceCache, 7); + + // + // Now handle the data part. + // + + if (sequenceQueue_.peek(requestSequenceNum, requestOpcode) && + requestSequenceNum == sequenceNum) + { + // + // We've found the request that generated this reply. + // It is possible to compress the reply based on the + // specific request type. + // + + sequenceQueue_.pop(requestSequenceNum, requestOpcode, + requestData[0], requestData[1], requestData[2]); + + // + // If differential compression is disabled + // then use the most simple encoding. + // + + if (control -> LocalDeltaCompression == 0) + { + int result = handleFastReadReply(encodeBuffer, requestOpcode, + inputMessage, inputLength); + if (result < 0) + { + return -1; + } + else if (result > 0) + { + continue; + } + } + + switch (requestOpcode) + { + case X_AllocColor: + { + const unsigned char *nextSrc = inputMessage + 8; + for (unsigned int i = 0; i < 3; i++) + { + unsigned int colorValue = GetUINT(nextSrc, bigEndian_); + nextSrc += 2; + if (colorValue == requestData[i]) + encodeBuffer.encodeBoolValue(1); + else + { + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeValue(colorValue - colorValue, 16, 6); + } + } + unsigned int pixel = GetULONG(inputMessage + 16, bigEndian_); + encodeBuffer.encodeValue(pixel, 32, 9); + + priority_++; + } + break; + case X_GetAtomName: + { + unsigned int nameLength = GetUINT(inputMessage + 8, bigEndian_); + encodeBuffer.encodeValue(nameLength, 16, 6); + const unsigned char *nextSrc = inputMessage + 32; + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, nameLength); + + priority_++; + } + break; + case X_GetGeometry: + { + // + // TODO: This obtains a satisfactory 10:1, but + // could be cached to leverage the big amount + // of such requests issued by QT clients. + // + + encodeBuffer.encodeCachedValue(inputMessage[1], 8, + serverCache_ -> depthCache); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> getGeometryRootCache, 9); + const unsigned char *nextSrc = inputMessage + 12; + for (unsigned int i = 0; i < 5; i++) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *serverCache_ -> getGeometryGeomCache[i], 8); + nextSrc += 2; + } + + priority_++; + } + break; + case X_GetInputFocus: + { + // + // Is it a real X_GetInputFocus or a + // masqueraded reply? + // + + if (requestData[0] == X_GetInputFocus) + { + encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> getInputFocusWindowCache); + + priority_++; + } + else + { + // + // TODO: We are not setting priority in case + // of replies other than real X_GetInputFocus + // or X_NXGetUnpackParameters. We should check + // once again that this is OK. + // + + #ifdef TEST + *logofs << "handleRead: Received tainted X_GetInputFocus reply " + << "for request OPCODE#" << requestData[0] << " with " + << "sequence " << sequenceNum << ".\n" + << logofs_flush; + #endif + + // + // Don't encode any data in case of sync + // messages or any other reply for which + // opcode is enough. + // + + if (requestData[0] == opcodeStore_ -> getUnpackParameters) + { + for (int i = 0; i < PACK_METHOD_LIMIT; i++) + { + encodeBuffer.encodeBoolValue(control -> LocalUnpackMethods[i]); + } + + priority_++; + } + else if (requestData[0] == opcodeStore_ -> getShmemParameters) + { + if (handleShmemReply(encodeBuffer, requestOpcode, requestData[1], + inputMessage, inputLength) < 0) + { + return -1; + } + + priority_++; + } + else if (requestData[0] == opcodeStore_ -> getFontParameters) + { + if (handleFontReply(encodeBuffer, requestOpcode, + inputMessage, inputLength) < 0) + { + return -1; + } + } + + // + // Account this data to the original opcode. + // + + requestOpcode = requestData[0]; + } + } + break; + case X_GetKeyboardMapping: + { + unsigned int keysymsPerKeycode = (unsigned int) inputMessage[1]; + if (ServerCache::getKeyboardMappingLastMap.compare(inputLength - 32, + inputMessage + 32) && (keysymsPerKeycode == + ServerCache::getKeyboardMappingLastKeysymsPerKeycode)) + { + encodeBuffer.encodeBoolValue(1); + + priority_++; + + break; + } + ServerCache::getKeyboardMappingLastKeysymsPerKeycode = keysymsPerKeycode; + encodeBuffer.encodeBoolValue(0); + unsigned int numKeycodes = + (((inputLength - 32) / keysymsPerKeycode) >> 2); + encodeBuffer.encodeValue(numKeycodes, 8); + encodeBuffer.encodeValue(keysymsPerKeycode, 8, 4); + const unsigned char *nextSrc = inputMessage + 32; + unsigned char previous = 0; + for (unsigned int count = numKeycodes * keysymsPerKeycode; + count; --count) + { + unsigned int keysym = GetULONG(nextSrc, bigEndian_); + nextSrc += 4; + if (keysym == NoSymbol) + encodeBuffer.encodeBoolValue(1); + else + { + encodeBuffer.encodeBoolValue(0); + unsigned int first3Bytes = (keysym >> 8); + encodeBuffer.encodeCachedValue(first3Bytes, 24, + serverCache_ -> getKeyboardMappingKeysymCache, 9); + unsigned char lastByte = (unsigned char) (keysym & 0xff); + encodeBuffer.encodeCachedValue(lastByte - previous, 8, + serverCache_ -> getKeyboardMappingLastByteCache, 5); + previous = lastByte; + } + } + + priority_++; + } + break; + case X_GetModifierMapping: + { + encodeBuffer.encodeValue((unsigned int) inputMessage[1], 8); + const unsigned char *nextDest = inputMessage + 32; + if (ServerCache::getModifierMappingLastMap.compare(inputLength - 32, + nextDest)) + { + encodeBuffer.encodeBoolValue(1); + + priority_++; + + break; + } + encodeBuffer.encodeBoolValue(0); + for (unsigned int count = inputLength - 32; count; count--) + { + unsigned char next = *nextDest++; + if (next == 0) + encodeBuffer.encodeBoolValue(1); + else + { + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeValue(next, 8); + } + } + + priority_++; + } + break; + case X_GetProperty: + { + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_GetProperty); + + hit = handleEncode(encodeBuffer, serverCache_, messageStore, + requestOpcode, inputMessage, inputLength); + + priority_++; + } + break; + case X_GetSelectionOwner: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> getSelectionOwnerCache, 9); + priority_++; + } + break; + case X_GetWindowAttributes: + { + encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> visualCache); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 12, bigEndian_), + 16, serverCache_ -> getWindowAttributesClassCache, 3); + encodeBuffer.encodeCachedValue(inputMessage[14], 8, + serverCache_ -> getWindowAttributesBitGravityCache); + encodeBuffer.encodeCachedValue(inputMessage[15], 8, + serverCache_ -> getWindowAttributesWinGravityCache); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), + 32, serverCache_ -> getWindowAttributesPlanesCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 20, bigEndian_), + 32, serverCache_ -> getWindowAttributesPixelCache, 9); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[24]); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[25]); + encodeBuffer.encodeValue((unsigned int) inputMessage[26], 2); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[27]); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 28, bigEndian_), + 29, serverCache_ -> colormapCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 32, bigEndian_), + 32, serverCache_ -> getWindowAttributesAllEventsCache); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 36, bigEndian_), + 32, serverCache_ -> getWindowAttributesYourEventsCache); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 40, bigEndian_), + 16, serverCache_ -> getWindowAttributesDontPropagateCache); + + priority_++; + } + break; + case X_GrabKeyboard: + case X_GrabPointer: + { + encodeBuffer.encodeValue((unsigned int) inputMessage[1], 3); + + priority_++; + } + break; + case X_InternAtom: + { + encodeBuffer.encodeValue(GetULONG(inputMessage + 8, bigEndian_), 29, 9); + + priority_++; + } + break; + case X_ListExtensions: + { + encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 8); + unsigned int numExtensions = (unsigned int) inputMessage[1]; + encodeBuffer.encodeValue(numExtensions, 8); + const unsigned char *nextSrc = inputMessage + 32; + + for (; numExtensions; numExtensions--) + { + unsigned int length = (unsigned int) (*nextSrc++); + + encodeBuffer.encodeValue(length, 8); + + #ifdef HIDE_MIT_SHM_EXTENSION + + if (!strncmp((char *) nextSrc, "MIT-SHM", 7)) + { + #ifdef TEST + *logofs << "handleRead: Hiding MIT-SHM extension in reply.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) nextSrc, "NO-MIT-", 7); + } + + #endif + + #ifdef HIDE_BIG_REQUESTS_EXTENSION + + if (!strncmp((char *) nextSrc, "BIG-REQUESTS", 12)) + { + #ifdef TEST + *logofs << "handleRead: Hiding BIG-REQUESTS extension in reply.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) nextSrc, "NO-BIG-REQUE", 12); + } + + #endif + + #ifdef HIDE_XKEYBOARD_EXTENSION + + if (!strncmp((char *) nextSrc, "XKEYBOARD", 9)) + { + #ifdef TEST + *logofs << "handleRead: Hiding XKEYBOARD extension in reply.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) nextSrc, "NO-XKEYBO", 9); + } + + #endif + + #ifdef HIDE_XFree86_Bigfont_EXTENSION + + if (!strncmp((char *) nextSrc, "XFree86-Bigfont", 15)) + { + #ifdef TEST + *logofs << "handleRead: Hiding XFree86-Bigfont extension in reply.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) nextSrc, "NO-XFree86-Bigf", 15); + } + + #endif + + #ifdef HIDE_SHAPE_EXTENSION + + if (!strncmp((char *) nextSrc, "SHAPE", 5)) + { + #ifdef TEST + *logofs << "handleRead: Hiding SHAPE extension in reply.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) nextSrc, "NO-SH", 5); + } + + #endif + + // + // Check if user disabled RENDER extension. + // + + if (control -> HideRender == 1 && + !strncmp((char *) nextSrc, "RENDER", 6)) + { + #ifdef TEST + *logofs << "handleRead: Hiding RENDER extension in reply.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) nextSrc, "NO-REN", 6); + } + + for (; length; length--) + { + encodeBuffer.encodeValue((unsigned int) (*nextSrc++), 8); + } + } + + priority_++; + } + break; + case X_ListFonts: + { + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_ListFonts); + + if (handleEncodeCached(encodeBuffer, serverCache_, messageStore, + inputMessage, inputLength)) + { + priority_++; + + hit = 1; + + break; + } + + encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 8); + unsigned int numFonts = GetUINT(inputMessage + 8, bigEndian_); + encodeBuffer.encodeValue(numFonts, 16, 6); + + // Differential encoding. + encodeBuffer.encodeBoolValue(1); + + const unsigned char* nextSrc = inputMessage + 32; + for (; numFonts; numFonts--) + { + unsigned int length = (unsigned int) (*nextSrc++); + encodeBuffer.encodeValue(length, 8); + + // Since ProtoStep7 (#issue 108) + encodeBuffer.encodeTextData(nextSrc, length); + + nextSrc += length; + } + + priority_++; + } + break; + case X_LookupColor: + case X_AllocNamedColor: + { + const unsigned char *nextSrc = inputMessage + 8; + if (requestOpcode == X_AllocNamedColor) + { + encodeBuffer.encodeValue(GetULONG(nextSrc, bigEndian_), 32, 9); + nextSrc += 4; + } + unsigned int count = 3; + do + { + unsigned int exactColor = GetUINT(nextSrc, bigEndian_); + encodeBuffer.encodeValue(exactColor, 16, 9); + unsigned int visualColor = GetUINT(nextSrc + 6, bigEndian_) - + exactColor; + encodeBuffer.encodeValue(visualColor, 16, 5); + nextSrc += 2; + } + while (--count); + + priority_++; + } + break; + case X_QueryBestSize: + { + encodeBuffer.encodeValue(GetUINT(inputMessage + 8, bigEndian_), 16, 8); + encodeBuffer.encodeValue(GetUINT(inputMessage + 10, bigEndian_), 16, 8); + + priority_++; + } + break; + case X_QueryColors: + { + // Differential encoding. + encodeBuffer.encodeBoolValue(1); + + unsigned int numColors = ((inputLength - 32) >> 3); + const unsigned char *nextSrc = inputMessage + 40; + unsigned char *nextDest = (unsigned char *) inputMessage + 38; + for (unsigned int c = 1; c < numColors; c++) + { + for (unsigned int i = 0; i < 6; i++) + *nextDest++ = *nextSrc++; + nextSrc += 2; + } + unsigned int colorsLength = numColors * 6; + if (serverCache_ -> queryColorsLastReply.compare(colorsLength, + inputMessage + 32)) + encodeBuffer.encodeBoolValue(1); + else + { + const unsigned char *nextSrc = inputMessage + 32; + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeValue(numColors, 16, 5); + for (numColors *= 3; numColors; numColors--) + { + encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16); + nextSrc += 2; + } + } + + priority_++; + } + break; + case X_QueryExtension: + { + if (requestData[0] == X_QueryExtension) + { + // + // Value in requestData[0] will be nonzero + // if the request is for an extension that + // we should hide to the X client. + // + + if (requestData[1]) + { + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeValue(0, 8); + } + else + { + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[8]); + encodeBuffer.encodeValue((unsigned int) inputMessage[9], 8); + } + + encodeBuffer.encodeValue((unsigned int) inputMessage[10], 8); + encodeBuffer.encodeValue((unsigned int) inputMessage[11], 8); + + if (requestData[2] == X_NXInternalShapeExtension) + { + opcodeStore_ -> shapeExtension = inputMessage[9]; + + #ifdef TEST + *logofs << "handleRead: Shape extension opcode for FD#" << fd_ + << " is " << (unsigned int) opcodeStore_ -> shapeExtension + << ".\n" << logofs_flush; + #endif + } + else if (requestData[2] == X_NXInternalRenderExtension) + { + opcodeStore_ -> renderExtension = inputMessage[9]; + + #ifdef TEST + *logofs << "handleRead: Render extension opcode for FD#" << fd_ + << " is " << (unsigned int) opcodeStore_ -> renderExtension + << ".\n" << logofs_flush; + #endif + } + + priority_++; + } + else + { + #ifdef TEST + *logofs << "handleRead: Received tainted X_QueryExtension reply " + << "for request OPCODE#" << requestData[0] << " with " + << "sequence " << sequenceNum << ".\n" + << logofs_flush; + #endif + + if (requestData[0] == opcodeStore_ -> getShmemParameters) + { + if (handleShmemReply(encodeBuffer, requestOpcode, requestData[1], + inputMessage, inputLength) < 0) + { + return -1; + } + + priority_++; + } + // + // Account this data to the original opcode. + // + + requestOpcode = requestData[0]; + } + } + break; + case X_QueryFont: + { + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_QueryFont); + + if (handleEncodeCached(encodeBuffer, serverCache_, messageStore, + inputMessage, inputLength)) + { + priority_++; + + hit = 1; + + break; + } + + // Differential encoding. + encodeBuffer.encodeBoolValue(1); + + unsigned int numProperties = GetUINT(inputMessage + 46, bigEndian_); + unsigned int numCharInfos = GetULONG(inputMessage + 56, bigEndian_); + encodeBuffer.encodeValue(numProperties, 16, 8); + encodeBuffer.encodeValue(numCharInfos, 32, 10); + handleEncodeCharInfo(inputMessage + 8, encodeBuffer); + handleEncodeCharInfo(inputMessage + 24, encodeBuffer); + encodeBuffer.encodeValue(GetUINT(inputMessage + 40, bigEndian_), 16, 9); + encodeBuffer.encodeValue(GetUINT(inputMessage + 42, bigEndian_), 16, 9); + encodeBuffer.encodeValue(GetUINT(inputMessage + 44, bigEndian_), 16, 9); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[48]); + encodeBuffer.encodeValue((unsigned int) inputMessage[49], 8); + encodeBuffer.encodeValue((unsigned int) inputMessage[50], 8); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[51]); + encodeBuffer.encodeValue(GetUINT(inputMessage + 52, bigEndian_), 16, 9); + encodeBuffer.encodeValue(GetUINT(inputMessage + 54, bigEndian_), 16, 9); + const unsigned char *nextSrc = inputMessage + 60; + unsigned int index; + + int end = 0; + + if (ServerCache::queryFontFontCache.lookup(numProperties * 8 + + numCharInfos * 12, nextSrc, index)) + { + encodeBuffer.encodeBoolValue(1); + encodeBuffer.encodeValue(index, 4); + + end = 1; + } + + if (end == 0) + { + encodeBuffer.encodeBoolValue(0); + for (; numProperties; numProperties--) + { + encodeBuffer.encodeValue(GetULONG(nextSrc, bigEndian_), 32, 9); + encodeBuffer.encodeValue(GetULONG(nextSrc + 4, bigEndian_), 32, 9); + nextSrc += 8; + } + for (; numCharInfos; numCharInfos--) + { + handleEncodeCharInfo(nextSrc, encodeBuffer); + + nextSrc += 12; + } + } + + priority_++; + } + break; + case X_QueryPointer: + { + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> queryPointerRootCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), + 29, serverCache_ -> queryPointerChildCache, 9); + unsigned int rootX = GetUINT(inputMessage + 16, bigEndian_); + unsigned int rootY = GetUINT(inputMessage + 18, bigEndian_); + unsigned int eventX = GetUINT(inputMessage + 20, bigEndian_); + unsigned int eventY = GetUINT(inputMessage + 22, bigEndian_); + eventX -= rootX; + eventY -= rootY; + encodeBuffer.encodeCachedValue( + rootX - serverCache_ -> motionNotifyLastRootX, 16, + serverCache_ -> motionNotifyRootXCache, 8); + serverCache_ -> motionNotifyLastRootX = rootX; + encodeBuffer.encodeCachedValue( + rootY - serverCache_ -> motionNotifyLastRootY, 16, + serverCache_ -> motionNotifyRootYCache, 8); + serverCache_ -> motionNotifyLastRootY = rootY; + encodeBuffer.encodeCachedValue(eventX, 16, + serverCache_ -> motionNotifyEventXCache, 8); + encodeBuffer.encodeCachedValue(eventY, 16, + serverCache_ -> motionNotifyEventYCache, 8); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 24, bigEndian_), + 16, serverCache_ -> motionNotifyStateCache); + priority_++; + } + break; + case X_QueryTree: + { + // + // This was very inefficient. In practice + // it just copied data on the output. Now + // it obtains an average 7:1 compression + // and could optionally be cached. + // + + unsigned int children = GetUINT(inputMessage + 16, bigEndian_); + + encodeBuffer.encodeValue(children, 16, 8); + + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, + serverCache_ -> queryTreeWindowCache); + + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), 29, + serverCache_ -> queryTreeWindowCache); + + const unsigned char *next = inputMessage + 32; + + for (unsigned int i = 0; i < children; i++) + { + encodeBuffer.encodeCachedValue(GetULONG(next + (i * 4), bigEndian_), 29, + serverCache_ -> queryTreeWindowCache); + } + + priority_++; + } + break; + case X_TranslateCoords: + { + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> translateCoordsChildCache, 9); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 12, bigEndian_), + 16, serverCache_ -> translateCoordsXCache, 8); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 14, bigEndian_), + 16, serverCache_ -> translateCoordsYCache, 8); + priority_++; + } + break; + case X_GetImage: + { + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_GetImage); + + if (handleEncodeCached(encodeBuffer, serverCache_, messageStore, + inputMessage, inputLength)) + { + priority_++; + + hit = 1; + + break; + } + + // Depth. + encodeBuffer.encodeCachedValue(inputMessage[1], 8, + serverCache_ -> depthCache); + // Reply length. + encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 9); + + // Visual. + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29, + serverCache_ -> visualCache); + + // Since ProtoStep8 (#issue 108) + handleCopy(encodeBuffer, requestOpcode, messageStore -> + dataOffset, inputMessage, inputLength); + + priority_++; + } + break; + case X_GetPointerMapping: + { + encodeBuffer.encodeValue(inputMessage[1], 8, 4); + encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 4); + for (unsigned int i = 32; i < inputLength; i++) + encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8, 4); + + priority_++; + } + break; + case X_GetKeyboardControl: + { + encodeBuffer.encodeValue(inputMessage[1], 8, 2); + encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 8); + for (unsigned int i = 8; i < inputLength; i++) + encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8, 4); + + priority_++; + } + break; + default: + { + #ifdef PANIC + *logofs << "ServerChannel: PANIC! No matching request with " + << "OPCODE#" << (unsigned int) requestOpcode + << " for reply with sequence number " + << requestSequenceNum << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": No matching request with OPCODE#" + << (unsigned int) requestOpcode << " for reply with " + << "sequence number " << requestSequenceNum << ".\n"; + + return -1; + } + } + + bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) + + const char *cacheString = (hit ? "cached " : ""); + + *logofs << "handleRead: Handled " << cacheString << "reply to OPCODE#" + << (unsigned int) requestOpcode << " (" << DumpOpcode(requestOpcode) + << ") for FD#" << fd_ << " sequence " << serverSequence_ + << ". " << inputLength << " bytes in, " << bits << " bits (" + << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; + + #endif + + } // End of if (sequenceQueue_.peek(requestSequenceNum, requestOpcode) && ... + else + { + // + // We didn't push the request opcode. + // Check if fast encoding is required. + // + + requestOpcode = X_Reply; + + if (control -> LocalDeltaCompression == 0) + { + int result = handleFastReadReply(encodeBuffer, requestOpcode, + inputMessage, inputLength); + if (result < 0) + { + return -1; + } + else if (result > 0) + { + continue; + } + } + + // + // Group all replies whose opcode was not + // pushed in sequence number queue under + // the category 'generic reply'. + // + + #ifdef DEBUG + *logofs << "handleRead: Identified generic reply.\n" + << logofs_flush; + #endif + + MessageStore *messageStore = serverStore_ -> + getReplyStore(X_NXInternalGenericReply); + + hit = handleEncode(encodeBuffer, serverCache_, messageStore, + requestOpcode, inputMessage, inputLength); + + priority_++; + + bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) + + const char *cacheString = (hit ? "cached " : ""); + + *logofs << "handleRead: Handled " << cacheString << "generic reply " + << "OPCODE#" << X_NXInternalGenericReply << " for FD#" << fd_ + << " sequence " << serverSequence_ << ". " << inputLength + << " bytes in, " << bits << " bits (" << ((float) bits) / 8 + << " bytes) out.\n" << logofs_flush; + + #endif + } + + if (hit) + { + statistics -> addCachedReply(requestOpcode); + } + + statistics -> addReplyBits(requestOpcode, inputLength << 3, bits); + + } // End of if (inputMessage[0] == 1) ... + else + { + // + // Event or error. + // + + unsigned char inputOpcode = *inputMessage; + + unsigned int inputSequence = GetUINT(inputMessage + 2, bigEndian_); + + // + // Check if this is an event which we can discard. + // + + if ((inputOpcode == Expose && enableExpose_ == 0) || + (inputOpcode == GraphicsExpose && enableGraphicsExpose_ == 0) || + (inputOpcode == NoExpose && enableNoExpose_ == 0)) + { + continue; + } + else if (shmemState_ != NULL && shmemState_ -> enabled == 1 && + inputOpcode == shmemState_ -> event && + checkShmemEvent(inputOpcode, inputSequence, + inputMessage) > 0) + { + continue; + } + else if (inputOpcode == MotionNotify) + { + // + // Save the motion event and send when another + // event or error is received or the motion ti- + // meout is elapsed. If a previous motion event + // was already saved, we replace it with the + // new one and don't reset the timeout, so we + // still have a motion event every given ms. + // + + memcpy(lastMotion_, inputMessage, 32); + + #ifdef TEST + *logofs << "handleRead: Saved suppressed motion event for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + continue; + } + else if (inputOpcode == X_Error) + { + // + // Check if this is an error that matches a + // sequence number for which we are expecting + // a reply. + // + + unsigned short int errorSequenceNum; + unsigned char errorOpcode; + + if (sequenceQueue_.peek(errorSequenceNum, errorOpcode) && + ((unsigned int) errorSequenceNum == inputSequence)) + { + sequenceQueue_.pop(errorSequenceNum, errorOpcode); + } + + // + // Check if error is due to an image commit + // generated at the end of a split. + // + + if (checkCommitError(*(inputMessage + 1), inputSequence, inputMessage) > 0) + { + #ifdef TEST + *logofs << "handleRead: Skipping error on image commit for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + continue; + } + + // + // Check if it's an error generated by a request + // concerning shared memory support. + // + + else if (shmemState_ != NULL && (shmemState_ -> sequence == + inputSequence || (shmemState_ -> enabled == 1 && + (shmemState_ -> opcode == *(inputMessage + 10) || + shmemState_ -> error == *(inputMessage + 1)))) && + checkShmemError(*(inputMessage + 1), inputSequence, + inputMessage) > 0) + { + #ifdef TEST + *logofs << "handleRead: Skipping error on shmem operation for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + continue; + } + } + // + // Check if user pressed the CTRL+ALT+SHIFT+ESC key + // sequence because was unable to kill the session + // through the normal procedure. + // + + if (inputOpcode == KeyPress) + { + if (checkKeyboardEvent(inputOpcode, inputSequence, inputMessage) == 1) + { + #ifdef TEST + *logofs << "handleRead: Removing the key sequence from the " + << "event stream for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + continue; + } + } + + // + // We are going to handle an event or error + // that's not a mouse motion. Prepend any + // saved motion to it. + // + + if (lastMotion_[0] != '\0') + { + if (handleMotion(encodeBuffer) < 0) + { + #ifdef PANIC + *logofs << "handleRead: PANIC! Can't encode motion event for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't encode motion event for FD#" + << fd_ << ".\n"; + + return -1; + } + } + + // + // Encode opcode and difference between + // current sequence and the last one. + // + + encodeBuffer.encodeOpcodeValue(inputOpcode, serverCache_ -> opcodeCache); + + unsigned int sequenceDiff = inputSequence - serverSequence_; + + serverSequence_ = inputSequence; + + #ifdef DEBUG + *logofs << "handleRead: Last server sequence number for FD#" + << fd_ << " is " << serverSequence_ << " with " + << "difference " << sequenceDiff << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(sequenceDiff, 16, + serverCache_ -> eventSequenceCache, 7); + + // + // If differential compression is disabled + // then use the most simple encoding. + // + + if (control -> LocalDeltaCompression == 0) + { + int result = handleFastReadEvent(encodeBuffer, inputOpcode, + inputMessage, inputLength); + if (result < 0) + { + return -1; + } + else if (result > 0) + { + continue; + } + } + + switch (inputOpcode) + { + case X_Error: + { + // + // Set the priority flag in the case of + // a X protocol error. This may restart + // the client if it was waiting for the + // reply. + // + + priority_++; + + unsigned char errorCode = *(inputMessage + 1); + + encodeBuffer.encodeCachedValue(errorCode, 8, + serverCache_ -> errorCodeCache); + + if (errorCode != 11 && errorCode != 8 && + errorCode != 15 && errorCode != 1) + { + encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 16); + } + + if (errorCode >= 18) + { + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, + serverCache_ -> errorMinorCache); + } + + encodeBuffer.encodeCachedValue(inputMessage[10], 8, + serverCache_ -> errorMajorCache); + + if (errorCode >= 18) + { + const unsigned char *nextSrc = inputMessage + 11; + for (unsigned int i = 11; i < 32; i++) + encodeBuffer.encodeValue(*nextSrc++, 8); + } + } + break; + case ButtonPress: + case ButtonRelease: + case KeyPress: + case KeyRelease: + case MotionNotify: + case EnterNotify: + case LeaveNotify: + { + // + // Set the priority in the case this is + // an event that the remote side may + // care to receive as soon as possible. + // + + switch (inputOpcode) + { + case ButtonPress: + case ButtonRelease: + case KeyPress: + case KeyRelease: + { + priority_++; + } + } + + unsigned char detail = inputMessage[1]; + if (*inputMessage == MotionNotify) + encodeBuffer.encodeBoolValue((unsigned int) detail); + else if ((*inputMessage == EnterNotify) || (*inputMessage == LeaveNotify)) + encodeBuffer.encodeValue((unsigned int) detail, 3); + else if (*inputMessage == KeyRelease) + { + if (detail == serverCache_ -> keyPressLastKey) + encodeBuffer.encodeBoolValue(1); + else + { + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeValue((unsigned int) detail, 8); + } + } + else if ((*inputMessage == ButtonPress) || (*inputMessage == ButtonRelease)) + encodeBuffer.encodeCachedValue(detail, 8, + serverCache_ -> buttonCache); + else + encodeBuffer.encodeValue((unsigned int) detail, 8); + unsigned int timestamp = GetULONG(inputMessage + 4, bigEndian_); + unsigned int timestampDiff = + timestamp - serverCache_ -> lastTimestamp; + serverCache_ -> lastTimestamp = timestamp; + encodeBuffer.encodeCachedValue(timestampDiff, 32, + serverCache_ -> motionNotifyTimestampCache, 9); + int skipRest = 0; + if (*inputMessage == KeyRelease) + { + skipRest = 1; + for (unsigned int i = 8; i < 31; i++) + { + if (inputMessage[i] != serverCache_ -> keyPressCache[i - 8]) + { + skipRest = 0; + break; + } + } + encodeBuffer.encodeBoolValue(skipRest); + } + + if (!skipRest) + { + const unsigned char *nextSrc = inputMessage + 8; + for (unsigned int i = 0; i < 3; i++) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29, + *serverCache_ -> motionNotifyWindowCache[i], 6); + nextSrc += 4; + } + unsigned int rootX = GetUINT(inputMessage + 20, bigEndian_); + unsigned int rootY = GetUINT(inputMessage + 22, bigEndian_); + unsigned int eventX = GetUINT(inputMessage + 24, bigEndian_); + unsigned int eventY = GetUINT(inputMessage + 26, bigEndian_); + eventX -= rootX; + eventY -= rootY; + encodeBuffer.encodeCachedValue(rootX - + serverCache_ -> motionNotifyLastRootX, 16, + serverCache_ -> motionNotifyRootXCache, 6); + serverCache_ -> motionNotifyLastRootX = rootX; + encodeBuffer.encodeCachedValue(rootY - + serverCache_ -> motionNotifyLastRootY, 16, + serverCache_ -> motionNotifyRootYCache, 6); + serverCache_ -> motionNotifyLastRootY = rootY; + encodeBuffer.encodeCachedValue(eventX, 16, + serverCache_ -> motionNotifyEventXCache, 6); + encodeBuffer.encodeCachedValue(eventY, 16, + serverCache_ -> motionNotifyEventYCache, 6); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 28, bigEndian_), + 16, serverCache_ -> motionNotifyStateCache); + if ((*inputMessage == EnterNotify) || (*inputMessage == LeaveNotify)) + encodeBuffer.encodeValue((unsigned int) inputMessage[30], 2); + else + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[30]); + if ((*inputMessage == EnterNotify) || (*inputMessage == LeaveNotify)) + encodeBuffer.encodeValue((unsigned int) inputMessage[31], 2); + else if (*inputMessage == KeyPress) + { + serverCache_ -> keyPressLastKey = detail; + for (unsigned int i = 8; i < 31; i++) + { + serverCache_ -> keyPressCache[i - 8] = inputMessage[i]; + } + } + } + } + break; + case ColormapNotify: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), + 29, serverCache_ -> colormapNotifyWindowCache, 8); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> colormapNotifyColormapCache, 8); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[12]); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[13]); + } + break; + case ConfigureNotify: + { + const unsigned char *nextSrc = inputMessage + 4; + for (unsigned int i = 0; i < 3; i++) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29, + *serverCache_ -> configureNotifyWindowCache[i], 9); + nextSrc += 4; + } + for (unsigned int j = 0; j < 5; j++) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *serverCache_ -> configureNotifyGeomCache[j], 8); + nextSrc += 2; + } + encodeBuffer.encodeBoolValue(*nextSrc); + } + break; + case CreateNotify: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), + 29, serverCache_ -> createNotifyWindowCache, 9); + unsigned int window = GetULONG(inputMessage + 8, bigEndian_); + encodeBuffer.encodeValue(window - + serverCache_ -> createNotifyLastWindow, 29, 5); + serverCache_ -> createNotifyLastWindow = window; + const unsigned char* nextSrc = inputMessage + 12; + for (unsigned int i = 0; i < 5; i++) + { + encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16, 9); + nextSrc += 2; + } + encodeBuffer.encodeBoolValue(*nextSrc); + } + break; + case Expose: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29, + serverCache_ -> exposeWindowCache, 9); + const unsigned char *nextSrc = inputMessage + 8; + for (unsigned int i = 0; i < 5; i++) + { + encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16, + *serverCache_ -> exposeGeomCache[i], 6); + nextSrc += 2; + } + } + break; + case FocusIn: + case FocusOut: + { + encodeBuffer.encodeValue((unsigned int) inputMessage[1], 3); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), + 29, serverCache_ -> focusInWindowCache, 9); + encodeBuffer.encodeValue((unsigned int) inputMessage[8], 2); + } + break; + case KeymapNotify: + { + if (ServerCache::lastKeymap.compare(31, inputMessage + 1)) + encodeBuffer.encodeBoolValue(1); + else + { + encodeBuffer.encodeBoolValue(0); + const unsigned char *nextSrc = inputMessage + 1; + for (unsigned int i = 1; i < 32; i++) + encodeBuffer.encodeValue((unsigned int) *nextSrc++, 8); + } + } + break; + case MapNotify: + case UnmapNotify: + case DestroyNotify: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), + 29, serverCache_ -> mapNotifyEventCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> mapNotifyWindowCache, 9); + if ((*inputMessage == MapNotify) || (*inputMessage == UnmapNotify)) + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[12]); + } + break; + case NoExpose: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), + 29, serverCache_ -> noExposeDrawableCache, 9); + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16, + serverCache_ -> noExposeMinorCache); + encodeBuffer.encodeCachedValue(inputMessage[10], 8, + serverCache_ -> noExposeMajorCache); + } + break; + case PropertyNotify: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), + 29, serverCache_ -> propertyNotifyWindowCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> propertyNotifyAtomCache, 9); + unsigned int timestamp = GetULONG(inputMessage + 12, bigEndian_); + unsigned int timestampDiff = + timestamp - serverCache_ -> lastTimestamp; + serverCache_ -> lastTimestamp = timestamp; + encodeBuffer.encodeValue(timestampDiff, 32, 9); + encodeBuffer.encodeBoolValue((unsigned int) inputMessage[16]); + } + break; + case ReparentNotify: + { + const unsigned char* nextSrc = inputMessage + 4; + for (unsigned int i = 0; i < 3; i++) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), + 29, serverCache_ -> reparentNotifyWindowCache, 9); + nextSrc += 4; + } + encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16, 6); + encodeBuffer.encodeValue(GetUINT(nextSrc + 2, bigEndian_), 16, 6); + encodeBuffer.encodeBoolValue((unsigned int)inputMessage[20]); + } + break; + case SelectionClear: + { + unsigned int timestamp = GetULONG(inputMessage + 4, bigEndian_); + unsigned int timestampDiff = timestamp - serverCache_ -> lastTimestamp; + serverCache_ -> lastTimestamp = timestamp; + encodeBuffer.encodeValue(timestampDiff, 32, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> selectionClearWindowCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), + 29, serverCache_ -> selectionClearAtomCache, 9); + } + break; + case SelectionRequest: + { + unsigned int timestamp = GetULONG(inputMessage + 4, bigEndian_); + unsigned int timestampDiff = timestamp - serverCache_ -> lastTimestamp; + serverCache_ -> lastTimestamp = timestamp; + encodeBuffer.encodeValue(timestampDiff, 32, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), + 29, serverCache_ -> selectionClearWindowCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), + 29, serverCache_ -> selectionClearWindowCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_), + 29, serverCache_ -> selectionClearAtomCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 20, bigEndian_), + 29, serverCache_ -> selectionClearAtomCache, 9); + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 24, bigEndian_), + 29, serverCache_ -> selectionClearAtomCache, 9); + } + break; + case VisibilityNotify: + { + encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), + 29, serverCache_ -> visibilityNotifyWindowCache, 9); + encodeBuffer.encodeValue((unsigned int) inputMessage[8], 2); + } + break; + default: + { + #ifdef TEST + *logofs << "handleRead: Using generic event compression " + << "for OPCODE#" << (unsigned int) inputOpcode + << ".\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(*(inputMessage + 1), 8, + serverCache_ -> genericEventCharCache); + + for (unsigned int i = 0; i < 14; i++) + { + encodeBuffer.encodeCachedValue(GetUINT(inputMessage + i * 2 + 4, bigEndian_), + 16, *serverCache_ -> genericEventIntCache[i]); + } + } + + } // switch (inputOpcode)... + + int bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) + + if (*inputMessage == X_Error) + { + unsigned char code = *(inputMessage + 1); + + *logofs << "handleRead: Handled error ERR_CODE#" + << (unsigned int) code << " for FD#" << fd_; + + *logofs << " RES_ID#" << GetULONG(inputMessage + 4, bigEndian_); + + *logofs << " MIN_OP#" << GetUINT(inputMessage + 8, bigEndian_); + + *logofs << " MAJ_OP#" << (unsigned int) *(inputMessage + 10); + + *logofs << " sequence " << inputSequence << ". " << inputLength + << " bytes in, " << bits << " bits (" << ((float) bits) / 8 + << " bytes) out.\n" << logofs_flush; + } + else + { + *logofs << "handleRead: Handled event OPCODE#" + << (unsigned int) *inputMessage << " for FD#" << fd_ + << " sequence " << inputSequence << ". " << inputLength + << " bytes in, " << bits << " bits (" << ((float) bits) / 8 + << " bytes) out.\n" << logofs_flush; + } + + #endif + + statistics -> addEventBits(*inputMessage, inputLength << 3, bits); + + } // End of if (inputMessage[0] == X_Reply) ... else ... + + } // End of if (firstReply_) ... else ... + + } // End of while ((inputMessage = readBuffer_.getMessage(inputLength)) != 0) ... + + // + // Check if we need to flush because of + // prioritized data. + // + + if (priority_ > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleRead: WARNING! Requesting flush " + << "because of " << priority_ << " prioritized " + << "messages for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + if (proxy -> handleAsyncPriority() < 0) + { + return -1; + } + + // + // Reset the priority flag. + // + + priority_ = 0; + } + + // + // Flush if we produced enough data. + // + + if (proxy -> canAsyncFlush() == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleRead: WARNING! Requesting flush " + << "because of token length exceeded.\n" + << logofs_flush; + #endif + + if (proxy -> handleAsyncFlush() < 0) + { + return -1; + } + } + + #if defined(TEST) || defined(INFO) + + if (transport_ -> pending() != 0 || + readBuffer_.checkMessage() != 0) + { + *logofs << "handleRead: PANIC! Buffer for X descriptor FD#" + << fd_ << " has " << transport_ -> pending() + << " bytes to read.\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + // + // Reset the read buffer. + // + + readBuffer_.fullReset(); + + return 1; +} + +// +// End of handleRead(). +// + +// +// Beginning of handleWrite(). +// + +int ServerChannel::handleWrite(const unsigned char *message, unsigned int length) +{ + #ifdef TEST + *logofs << "handleWrite: Called for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + // + // Create the buffer from which to + // decode messages. + // + + DecodeBuffer decodeBuffer(message, length); + + #if defined(TEST) || defined(INFO) || defined(FLUSH) + *logofs << "handleWrite: Decoding messages for FD#" << fd_ + << " with " << length << " bytes in the buffer.\n" + << logofs_flush; + #endif + + if (firstRequest_) + { + // + // Need to add the length of the first request + // because it was not present in the previous + // versions. Length of the first request was + // assumed to be the same as the encode buffer + // but this may be not the case if a different + // encoding is used. + // + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeValue(length, 8); + + unsigned int nextByte; + unsigned char *outputMessage = writeBuffer_.addMessage(length); + unsigned char *nextDest = outputMessage; + + for (unsigned int i = 0; i < length; i++) + { + decodeBuffer.decodeValue(nextByte, 8); + + *nextDest++ = (unsigned char) nextByte; + } + + if (*outputMessage == 0x42) + { + setBigEndian(1); + } + else + { + setBigEndian(0); + } + + #ifdef TEST + *logofs << "handleWrite: First request detected.\n" << logofs_flush; + #endif + + // + // Handle the fake authorization cookie. + // + + if (handleAuthorization(outputMessage) < 0) + { + return -1; + } + + firstRequest_ = 0; + + } // End of if (firstRequest_) + + // + // This was previously in a 'else' block. + // Due to the way the first request was + // handled, we could not decode multiple + // messages in the first frame. + // + + { // Start of the decoding block. + + unsigned char outputOpcode; + + unsigned char *outputMessage; + unsigned int outputLength; + + // + // Set when message is found in cache. + // + + int hit; + + while (decodeBuffer.decodeOpcodeValue(outputOpcode, clientCache_ -> opcodeCache, 1)) + { + hit = 0; + + // + // Splits are sent by client proxy outside the + // normal read loop. As we 'insert' splits in + // the real client-server X protocol, we must + // avoid to increment the sequence number or + // our clients would get confused. + // + + if (outputOpcode != opcodeStore_ -> splitData) + { + clientSequence_++; + clientSequence_ &= 0xffff; + + #ifdef DEBUG + *logofs << "handleWrite: Last client sequence number for FD#" + << fd_ << " is " << clientSequence_ << ".\n" + << logofs_flush; + #endif + } + else + { + // + // It's a split, not a normal + // burst of proxy data. + // + + handleSplit(decodeBuffer); + + continue; + } + + #ifdef SUSPEND + + if (clientSequence_ == 1000) + { + cerr << "Warning" << ": Exiting to test the resilience of the agent.\n"; + + sleep(2); + + HandleAbort(); + } + + #endif + + // + // Is differential encoding disabled? + // + + if (control -> RemoteDeltaCompression == 0) + { + int result = handleFastWriteRequest(decodeBuffer, outputOpcode, + outputMessage, outputLength); + if (result < 0) + { + return -1; + } + else if (result > 0) + { + continue; + } + } + + // + // General-purpose temp variables for + // decoding ints and chars. + // + + unsigned int value; + unsigned char cValue; + + #ifdef DEBUG + *logofs << "handleWrite: Going to handle request OPCODE#" + << (unsigned int) outputOpcode << " (" << DumpOpcode(outputOpcode) + << ") for FD#" << fd_ << " sequence " << clientSequence_ + << ".\n" << logofs_flush; + #endif + + switch (outputOpcode) + { + case X_AllocColor: + { + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> colormapCache); + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned char *nextDest = outputMessage + 8; + unsigned int colorData[3]; + + for (unsigned int i = 0; i < 3; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *(clientCache_ -> allocColorRGBCache[i]), 4); + PutUINT(value, nextDest, bigEndian_); + colorData[i] = value; + nextDest += 2; + } + + sequenceQueue_.push(clientSequence_, outputOpcode, + colorData[0], colorData[1], colorData[2]); + } + break; + case X_ReparentWindow: + { + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeValue(value, 16, 11); + PutUINT(value, outputMessage + 12, bigEndian_); + decodeBuffer.decodeValue(value, 16, 11); + PutUINT(value, outputMessage + 14, bigEndian_); + } + break; + case X_ChangeProperty: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ChangeProperty); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + unsigned char format; + decodeBuffer.decodeCachedValue(format, 8, + clientCache_ -> changePropertyFormatCache); + unsigned int dataLength; + decodeBuffer.decodeValue(dataLength, 32, 6); + outputLength = 24 + RoundUp4(dataLength * (format >> 3)); + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 2); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> changePropertyPropertyCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> changePropertyTypeCache, 9); + PutULONG(value, outputMessage + 12, bigEndian_); + outputMessage[16] = format; + PutULONG(dataLength, outputMessage + 20, bigEndian_); + unsigned char *nextDest = outputMessage + 24; + + if (format == 8) + { + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, dataLength); + } + else if (format == 32) + { + for (unsigned int i = 0; i < dataLength; i++) + { + decodeBuffer.decodeCachedValue(value, 32, + clientCache_ -> changePropertyData32Cache); + + PutULONG(value, nextDest, bigEndian_); + + nextDest += 4; + } + } + else + { + for (unsigned int i = 0; i < dataLength; i++) + { + decodeBuffer.decodeValue(value, 16); + + PutUINT(value, nextDest, bigEndian_); + + nextDest += 2; + } + } + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_SendEvent: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_SendEvent); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 44; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeBoolValue(value); + *(outputMessage + 1) = value; + decodeBuffer.decodeBoolValue(value); + if (value) + { + decodeBuffer.decodeBoolValue(value); + } + else + { + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + } + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 32, + clientCache_ -> sendEventMaskCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(*(outputMessage + 12), 8, + clientCache_ -> sendEventCodeCache); + decodeBuffer.decodeCachedValue(*(outputMessage + 13), 8, + clientCache_ -> sendEventByteDataCache); + decodeBuffer.decodeValue(value, 16, 4); + clientCache_ -> sendEventLastSequence += value; + clientCache_ -> sendEventLastSequence &= 0xffff; + PutUINT(clientCache_ -> sendEventLastSequence, outputMessage + 14, bigEndian_); + decodeBuffer.decodeCachedValue(value, 32, + clientCache_ -> sendEventIntDataCache); + PutULONG(value, outputMessage + 16, bigEndian_); + + for (unsigned int i = 20; i < 44; i++) + { + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache_ -> sendEventEventCache); + *(outputMessage + i) = cValue; + } + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_ChangeWindowAttributes: + { + unsigned int numAttrs; + decodeBuffer.decodeValue(numAttrs, 4); + outputLength = 12 + (numAttrs << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned int bitmask; + decodeBuffer.decodeCachedValue(bitmask, 15, + clientCache_ -> createWindowBitmaskCache); + PutULONG(bitmask, outputMessage + 8, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + unsigned int mask = 0x1; + for (unsigned int i = 0; i < 15; i++) + { + if (bitmask & mask) + { + decodeBuffer.decodeCachedValue(value, 32, + *clientCache_ -> createWindowAttrCache[i]); + PutULONG(value, nextDest, bigEndian_); + nextDest += 4; + } + mask <<= 1; + } + } + break; + case X_ClearArea: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ClearArea); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeBoolValue(value); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned char *nextDest = outputMessage + 8; + for (unsigned int i = 0; i < 4; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> clearAreaGeomCache[i], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_CloseFont: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 29, 5); + clientCache_ -> lastFont += value; + clientCache_ -> lastFont &= 0x1fffffff; + PutULONG(clientCache_ -> lastFont, outputMessage + 4, bigEndian_); + } + break; + case X_ConfigureWindow: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ConfigureWindow); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 12; + outputMessage = writeBuffer_.addMessage(outputLength); + writeBuffer_.registerPointer(&outputMessage); + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned int bitmask; + decodeBuffer.decodeCachedValue(bitmask, 7, + clientCache_ -> configureWindowBitmaskCache); + PutUINT(bitmask, outputMessage + 8, bigEndian_); + unsigned int mask = 0x1; + for (unsigned int i = 0; i < 7; i++) + { + if (bitmask & mask) + { + unsigned char* nextDest = writeBuffer_.addMessage(4); + outputLength += 4; + decodeBuffer.decodeCachedValue(value, CONFIGUREWINDOW_FIELD_WIDTH[i], + *clientCache_ -> configureWindowAttrCache[i], 8); + PutULONG(value, nextDest, bigEndian_); + nextDest += 4; + } + mask <<= 1; + } + writeBuffer_.unregisterPointer(); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_ConvertSelection: + { + outputLength = 24; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> convertSelectionRequestorCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned char* nextDest = outputMessage + 8; + for (unsigned int i = 0; i < 3; i++) + { + decodeBuffer.decodeCachedValue(value, 29, + *(clientCache_ -> convertSelectionAtomCache[i]), 9); + PutULONG(value, nextDest, bigEndian_); + nextDest += 4; + } + decodeBuffer.decodeValue(value, 32, 4); + clientCache_ -> convertSelectionLastTimestamp += value; + PutULONG(clientCache_ -> convertSelectionLastTimestamp, + nextDest, bigEndian_); + } + break; + case X_CopyArea: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_CopyArea); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 28; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 12, bigEndian_); + unsigned char *nextDest = outputMessage + 16; + for (unsigned int i = 0; i < 6; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> copyAreaGeomCache[i], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_CopyGC: + { + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 23, + clientCache_ -> createGCBitmaskCache); + PutULONG(value, outputMessage + 12, bigEndian_); + } + break; + case X_CopyPlane: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 12, bigEndian_); + unsigned char *nextDest = outputMessage + 16; + for (unsigned int i = 0; i < 6; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> copyPlaneGeomCache[i], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + decodeBuffer.decodeCachedValue(value, 32, + clientCache_ -> copyPlaneBitPlaneCache, 10); + PutULONG(value, outputMessage + 28, bigEndian_); + } + break; + case X_CreateGC: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_CreateGC); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + writeBuffer_.registerPointer(&outputMessage); + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeNewXidValue(value, clientCache_ -> lastId, + clientCache_ -> lastIdCache, clientCache_ -> gcCache, + clientCache_ -> freeGCCache); + + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned int offset = 8; + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + offset, bigEndian_); + offset += 4; + unsigned int bitmask; + decodeBuffer.decodeCachedValue(bitmask, 23, + clientCache_ -> createGCBitmaskCache); + PutULONG(bitmask, outputMessage + offset, bigEndian_); + unsigned int mask = 0x1; + for (unsigned int i = 0; i < 23; i++) + { + if (bitmask & mask) + { + unsigned char* nextDest = writeBuffer_.addMessage(4); + outputLength += 4; + unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i]; + if (fieldWidth <= 4) + decodeBuffer.decodeValue(value, fieldWidth); + else + decodeBuffer.decodeCachedValue(value, fieldWidth, + *clientCache_ -> createGCAttrCache[i]); + PutULONG(value, nextDest, bigEndian_); + } + mask <<= 1; + } + writeBuffer_.unregisterPointer(); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_ChangeGC: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ChangeGC); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 12; + outputMessage = writeBuffer_.addMessage(outputLength); + writeBuffer_.registerPointer(&outputMessage); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned int offset = 8; + unsigned int bitmask; + decodeBuffer.decodeCachedValue(bitmask, 23, + clientCache_ -> createGCBitmaskCache); + PutULONG(bitmask, outputMessage + offset, bigEndian_); + unsigned int mask = 0x1; + for (unsigned int i = 0; i < 23; i++) + { + if (bitmask & mask) + { + unsigned char* nextDest = writeBuffer_.addMessage(4); + outputLength += 4; + unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i]; + if (fieldWidth <= 4) + decodeBuffer.decodeValue(value, fieldWidth); + else + decodeBuffer.decodeCachedValue(value, fieldWidth, + *clientCache_ -> createGCAttrCache[i]); + PutULONG(value, nextDest, bigEndian_); + } + mask <<= 1; + } + writeBuffer_.unregisterPointer(); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_CreatePixmap: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_CreatePixmap); + + hit = handleDecode(decodeBuffer, clientCache_, messageStore, + outputOpcode, outputMessage, outputLength); + } + break; + case X_CreateWindow: + { + outputLength = 32; + outputMessage = writeBuffer_.addMessage(outputLength); + writeBuffer_.registerPointer(&outputMessage); + decodeBuffer.decodeCachedValue(cValue, 8, clientCache_ -> depthCache); + outputMessage[1] = cValue; + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 8, bigEndian_); + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeNewXidValue(value, clientCache_ -> lastId, + clientCache_ -> lastIdCache, clientCache_ -> windowCache, + clientCache_ -> freeWindowCache); + + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + unsigned int i; + for (i = 0; i < 6; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> createWindowGeomCache[i], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + decodeBuffer.decodeCachedValue(value, 29, clientCache_ -> visualCache); + PutULONG(value, outputMessage + 24, bigEndian_); + unsigned int bitmask; + decodeBuffer.decodeCachedValue(bitmask, 15, + clientCache_ -> createWindowBitmaskCache); + PutULONG(bitmask, outputMessage + 28, bigEndian_); + unsigned int mask = 0x1; + for (i = 0; i < 15; i++) + { + if (bitmask & mask) + { + nextDest = writeBuffer_.addMessage(4); + outputLength += 4; + decodeBuffer.decodeCachedValue(value, 32, + *clientCache_ -> createWindowAttrCache[i]); + PutULONG(value, nextDest, bigEndian_); + } + mask <<= 1; + } + writeBuffer_.unregisterPointer(); + } + break; + case X_DeleteProperty: + { + outputLength = 12; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeValue(value, 29, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + } + break; + case X_FillPoly: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_FillPoly); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + unsigned int numPoints; + + // Since ProtoStep10 (#issue 108) + decodeBuffer.decodeCachedValue(numPoints, 16, + clientCache_ -> fillPolyNumPointsCache, 4); + + outputLength = 16 + (numPoints << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeValue(value, 2); + outputMessage[12] = (unsigned char) value; + unsigned int relativeCoordMode; + decodeBuffer.decodeBoolValue(relativeCoordMode); + outputMessage[13] = (unsigned char) relativeCoordMode; + unsigned char *nextDest = outputMessage + 16; + unsigned int pointIndex = 0; + for (unsigned int i = 0; i < numPoints; i++) + { + if (relativeCoordMode) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> fillPolyXRelCache[pointIndex], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> fillPolyYRelCache[pointIndex], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + else + { + unsigned int x, y; + decodeBuffer.decodeBoolValue(value); + if (value) + { + decodeBuffer.decodeValue(value, 3); + x = clientCache_ -> fillPolyRecentX[value]; + y = clientCache_ -> fillPolyRecentY[value]; + } + else + { + decodeBuffer.decodeCachedValue(x, 16, + *clientCache_ -> fillPolyXAbsCache[pointIndex], 8); + decodeBuffer.decodeCachedValue(y, 16, + *clientCache_ -> fillPolyYAbsCache[pointIndex], 8); + clientCache_ -> fillPolyRecentX[clientCache_ -> fillPolyIndex] = x; + clientCache_ -> fillPolyRecentY[clientCache_ -> fillPolyIndex] = y; + clientCache_ -> fillPolyIndex++; + if (clientCache_ -> fillPolyIndex == 8) + clientCache_ -> fillPolyIndex = 0; + } + PutUINT(x, nextDest, bigEndian_); + nextDest += 2; + PutUINT(y, nextDest, bigEndian_); + nextDest += 2; + } + + if (++pointIndex == 10) pointIndex = 0; + } + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_FreeColors: + { + unsigned int numPixels; + decodeBuffer.decodeValue(numPixels, 16, 4); + outputLength = 12 + (numPixels << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> colormapCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeValue(value, 32, 4); + PutULONG(value, outputMessage + 8, bigEndian_); + unsigned char* nextDest = outputMessage + 12; + while (numPixels) + { + decodeBuffer.decodeValue(value, 32, 8); + PutULONG(value, nextDest, bigEndian_); + nextDest += 4; + numPixels--; + } + } + break; + case X_FreeCursor: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, clientCache_ -> cursorCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + } + break; + case X_FreeGC: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeFreeXidValue(value, clientCache_ -> freeGCCache); + + PutULONG(value, outputMessage + 4, bigEndian_); + } + break; + case X_FreePixmap: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeFreeXidValue(value, clientCache_ -> freeDrawableCache); + + PutULONG(value, outputMessage + 4, bigEndian_); + } + break; + case X_GetAtomName: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 29, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_GetGeometry: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_GetInputFocus: + { + outputLength = 4; + outputMessage = writeBuffer_.addMessage(outputLength); + + sequenceQueue_.push(clientSequence_, outputOpcode, outputOpcode); + } + break; + case X_GetModifierMapping: + { + outputLength = 4; + outputMessage = writeBuffer_.addMessage(outputLength); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_GetKeyboardMapping: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 8); + outputMessage[4] = value; + decodeBuffer.decodeValue(value, 8); + outputMessage[5] = value; + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_GetProperty: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_GetProperty); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + // + // Save a reference to identify the reply. + // + + unsigned int property = GetULONG(outputMessage + 8, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode, property); + + break; + } + + outputLength = 24; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeBoolValue(value); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned int property; + decodeBuffer.decodeValue(property, 29, 9); + PutULONG(property, outputMessage + 8, bigEndian_); + decodeBuffer.decodeValue(value, 29, 9); + PutULONG(value, outputMessage + 12, bigEndian_); + decodeBuffer.decodeValue(value, 32, 2); + PutULONG(value, outputMessage + 16, bigEndian_); + decodeBuffer.decodeValue(value, 32, 8); + PutULONG(value, outputMessage + 20, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode, property); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_GetSelectionOwner: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> getSelectionOwnerSelectionCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_GrabButton: + case X_GrabPointer: + { + outputLength = 24; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeBoolValue(value); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> grabButtonEventMaskCache); + PutUINT(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeBoolValue(value); + outputMessage[10] = (unsigned char) value; + decodeBuffer.decodeBoolValue(value); + outputMessage[11] = (unsigned char) value; + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> grabButtonConfineCache, 9); + PutULONG(value, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> cursorCache, 9); + PutULONG(value, outputMessage + 16, bigEndian_); + if (outputOpcode == X_GrabButton) + { + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache_ -> grabButtonButtonCache); + outputMessage[20] = cValue; + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> grabButtonModifierCache); + PutUINT(value, outputMessage + 22, bigEndian_); + } + else + { + decodeBuffer.decodeValue(value, 32, 4); + clientCache_ -> grabKeyboardLastTimestamp += value; + PutULONG(clientCache_ -> grabKeyboardLastTimestamp, + outputMessage + 20, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + } + break; + case X_GrabKeyboard: + { + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeBoolValue(value); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeValue(value, 32, 4); + clientCache_ -> grabKeyboardLastTimestamp += value; + PutULONG(clientCache_ -> grabKeyboardLastTimestamp, outputMessage + 8, + bigEndian_); + decodeBuffer.decodeBoolValue(value); + outputMessage[12] = (unsigned char) value; + decodeBuffer.decodeBoolValue(value); + outputMessage[13] = (unsigned char) value; + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_GrabServer: + case X_UngrabServer: + case X_NoOperation: + { + #ifdef DEBUG + *logofs << "handleWrite: Managing (probably tainted) X_NoOperation request for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + outputLength = 4; + outputMessage = writeBuffer_.addMessage(outputLength); + } + break; + case X_PolyText8: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyText8); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> polyTextCacheX); + clientCache_ -> polyTextLastX += value; + clientCache_ -> polyTextLastX &= 0xffff; + PutUINT(clientCache_ -> polyTextLastX, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> polyTextCacheY); + clientCache_ -> polyTextLastY += value; + clientCache_ -> polyTextLastY &= 0xffff; + PutUINT(clientCache_ -> polyTextLastY, outputMessage + 14, bigEndian_); + unsigned int addedLength = 0; + writeBuffer_.registerPointer(&outputMessage); + for (;;) + { + decodeBuffer.decodeBoolValue(value); + if (!value) + break; + unsigned int textLength; + decodeBuffer.decodeValue(textLength, 8); + if (textLength == 255) + { + addedLength += 5; + unsigned char *nextSegment = writeBuffer_.addMessage(5); + *nextSegment = (unsigned char) textLength; + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> polyTextFontCache); + PutULONG(value, nextSegment + 1, 1); + } + else + { + addedLength += (textLength + 2); + unsigned char *nextSegment = + writeBuffer_.addMessage(textLength + 2); + *nextSegment = (unsigned char) textLength; + unsigned char *nextDest = nextSegment + 1; + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache_ -> polyTextDeltaCache); + *nextDest++ = cValue; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, textLength); + + nextDest += textLength; + } + } + outputLength += addedLength; + unsigned int mod4 = (addedLength & 0x3); + if (mod4) + { + unsigned int extra = 4 - mod4; + unsigned char *nextDest = writeBuffer_.addMessage(extra); + for (unsigned int i = 0; i < extra; i++) + *nextDest++ = 0; + outputLength += extra; + } + writeBuffer_.unregisterPointer(); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_PolyText16: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyText16); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> polyTextCacheX); + clientCache_ -> polyTextLastX += value; + clientCache_ -> polyTextLastX &= 0xffff; + PutUINT(clientCache_ -> polyTextLastX, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> polyTextCacheY); + clientCache_ -> polyTextLastY += value; + clientCache_ -> polyTextLastY &= 0xffff; + PutUINT(clientCache_ -> polyTextLastY, outputMessage + 14, bigEndian_); + unsigned int addedLength = 0; + writeBuffer_.registerPointer(&outputMessage); + for (;;) + { + decodeBuffer.decodeBoolValue(value); + if (!value) + break; + unsigned int textLength; + decodeBuffer.decodeValue(textLength, 8); + if (textLength == 255) + { + addedLength += 5; + unsigned char *nextSegment = writeBuffer_.addMessage(5); + *nextSegment = (unsigned char) textLength; + decodeBuffer.decodeCachedValue(value, 29, clientCache_ -> polyTextFontCache); + PutULONG(value, nextSegment + 1, 1); + } + else + { + addedLength += (textLength * 2 + 2); + unsigned char *nextSegment = + writeBuffer_.addMessage(textLength * 2 + 2); + *nextSegment = (unsigned char) textLength; + unsigned char *nextDest = nextSegment + 1; + decodeBuffer.decodeCachedValue(cValue, 8, clientCache_ -> polyTextDeltaCache); + *nextDest++ = cValue; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, textLength * 2); + + nextDest += textLength * 2; + } + } + outputLength += addedLength; + + unsigned int mod4 = (addedLength & 0x3); + if (mod4) + { + unsigned int extra = 4 - mod4; + unsigned char *nextDest = writeBuffer_.addMessage(extra); + for (unsigned int i = 0; i < extra; i++) + *nextDest++ = 0; + outputLength += extra; + } + writeBuffer_.unregisterPointer(); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_ImageText8: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ImageText8); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + unsigned int textLength; + decodeBuffer.decodeCachedValue(textLength, 8, + clientCache_ -> imageTextLengthCache, 4); + outputLength = 16 + RoundUp4(textLength); + outputMessage = writeBuffer_.addMessage(outputLength); + outputMessage[1] = (unsigned char) textLength; + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> imageTextCacheX); + clientCache_ -> imageTextLastX += value; + clientCache_ -> imageTextLastX &= 0xffff; + PutUINT(clientCache_ -> imageTextLastX, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> imageTextCacheY); + clientCache_ -> imageTextLastY += value; + clientCache_ -> imageTextLastY &= 0xffff; + PutUINT(clientCache_ -> imageTextLastY, outputMessage + 14, bigEndian_); + unsigned char *nextDest = outputMessage + 16; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, textLength); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_ImageText16: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_ImageText16); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + unsigned int textLength; + decodeBuffer.decodeCachedValue(textLength, 8, + clientCache_ -> imageTextLengthCache, 4); + outputLength = 16 + RoundUp4(textLength * 2); + outputMessage = writeBuffer_.addMessage(outputLength); + outputMessage[1] = (unsigned char) textLength; + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> imageTextCacheX); + clientCache_ -> imageTextLastX += value; + clientCache_ -> imageTextLastX &= 0xffff; + PutUINT(clientCache_ -> imageTextLastX, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> imageTextCacheY); + clientCache_ -> imageTextLastY += value; + clientCache_ -> imageTextLastY &= 0xffff; + PutUINT(clientCache_ -> imageTextLastY, outputMessage + 14, bigEndian_); + unsigned char *nextDest = outputMessage + 16; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, textLength * 2); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_InternAtom: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_InternAtom); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + sequenceQueue_.push(clientSequence_, outputOpcode); + + break; + } + + unsigned int nameLength; + decodeBuffer.decodeValue(nameLength, 16, 6); + outputLength = RoundUp4(nameLength) + 8; + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(nameLength, outputMessage + 4, bigEndian_); + decodeBuffer.decodeBoolValue(value); + outputMessage[1] = (unsigned char) value; + unsigned char *nextDest = outputMessage + 8; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, nameLength); + + sequenceQueue_.push(clientSequence_, outputOpcode); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_ListExtensions: + { + outputLength = 4; + outputMessage = writeBuffer_.addMessage(outputLength); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_ListFonts: + { + unsigned int textLength; + decodeBuffer.decodeValue(textLength, 16, 6); + outputLength = 8 + RoundUp4(textLength); + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(textLength, outputMessage + 6, bigEndian_); + decodeBuffer.decodeValue(value, 16, 6); + PutUINT(value, outputMessage + 4, bigEndian_); + unsigned char* nextDest = outputMessage + 8; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, textLength); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_LookupColor: + case X_AllocNamedColor: + { + unsigned int textLength; + decodeBuffer.decodeValue(textLength, 16, 6); + outputLength = 12 + RoundUp4(textLength); + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> colormapCache); + PutULONG(value, outputMessage + 4, bigEndian_); + PutUINT(textLength, outputMessage + 8, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, textLength); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_MapWindow: + case X_UnmapWindow: + case X_MapSubwindows: + case X_GetWindowAttributes: + case X_DestroyWindow: + case X_DestroySubwindows: + case X_QueryPointer: + case X_QueryTree: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + + if (outputOpcode == X_DestroyWindow) // Since ProtoStep7 (#issue 108) + { + decodeBuffer.decodeFreeXidValue(value, clientCache_ -> freeWindowCache); + } + else + { + decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache); + } + + PutULONG(value, outputMessage + 4, bigEndian_); + if (outputOpcode == X_QueryPointer || + outputOpcode == X_GetWindowAttributes || + outputOpcode == X_QueryTree) + { + sequenceQueue_.push(clientSequence_, outputOpcode); + } + } + break; + case X_OpenFont: + { + unsigned int nameLength; + decodeBuffer.decodeValue(nameLength, 16, 7); + outputLength = RoundUp4(12 + nameLength); + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(nameLength, outputMessage + 8, bigEndian_); + decodeBuffer.decodeValue(value, 29, 5); + clientCache_ -> lastFont += value; + clientCache_ -> lastFont &= 0x1fffffff; + PutULONG(clientCache_ -> lastFont, outputMessage + 4, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeTextData(nextDest, nameLength); + } + break; + case X_PolyFillRectangle: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyFillRectangle); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 12; + outputMessage = writeBuffer_.addMessage(outputLength); + writeBuffer_.registerPointer(&outputMessage); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0, lastWidth = 0, lastHeight = 0; + unsigned int numRectangles = 0; + + for (;;) + { + outputLength += 8; + writeBuffer_.addMessage(8); + unsigned char *nextDest = outputMessage + 12 + + (numRectangles << 3); + numRectangles++; + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillRectangleCacheX[index], 8); + value += lastX; + PutUINT(value, nextDest, bigEndian_); + lastX = value; + nextDest += 2; + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillRectangleCacheY[index], 8); + value += lastY; + PutUINT(value, nextDest, bigEndian_); + lastY = value; + nextDest += 2; + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillRectangleCacheWidth[index], 8); + value += lastWidth; + PutUINT(value, nextDest, bigEndian_); + lastWidth = value; + nextDest += 2; + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillRectangleCacheHeight[index], 8); + value += lastHeight; + PutUINT(value, nextDest, bigEndian_); + lastHeight = value; + nextDest += 2; + + if (++index == 4) index = 0; + + decodeBuffer.decodeBoolValue(value); + + if (!value) break; + } + writeBuffer_.unregisterPointer(); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_PolyFillArc: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyFillArc); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 12; + outputMessage = writeBuffer_.addMessage(outputLength); + writeBuffer_.registerPointer(&outputMessage); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0, + lastWidth = 0, lastHeight = 0, + lastAngle1 = 0, lastAngle2 = 0; + + unsigned int numArcs = 0; + + for (;;) + { + outputLength += 12; + writeBuffer_.addMessage(12); + + unsigned char *nextDest = outputMessage + 12 + + (numArcs * 12); + numArcs++; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillArcCacheX[index], 8); + value += lastX; + PutUINT(value, nextDest, bigEndian_); + lastX = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillArcCacheY[index], 8); + value += lastY; + PutUINT(value, nextDest, bigEndian_); + lastY = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillArcCacheWidth[index], 8); + value += lastWidth; + PutUINT(value, nextDest, bigEndian_); + lastWidth = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillArcCacheHeight[index], 8); + value += lastHeight; + PutUINT(value, nextDest, bigEndian_); + lastHeight = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillArcCacheAngle1[index], 8); + value += lastAngle1; + PutUINT(value, nextDest, bigEndian_); + lastAngle1 = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyFillArcCacheAngle2[index], 8); + value += lastAngle2; + PutUINT(value, nextDest, bigEndian_); + lastAngle2 = value; + nextDest += 2; + + if (++index == 2) index = 0; + + decodeBuffer.decodeBoolValue(value); + + if (!value) break; + } + writeBuffer_.unregisterPointer(); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_PolyArc: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyArc); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + outputLength = 12; + outputMessage = writeBuffer_.addMessage(outputLength); + writeBuffer_.registerPointer(&outputMessage); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0, + lastWidth = 0, lastHeight = 0, + lastAngle1 = 0, lastAngle2 = 0; + + unsigned int numArcs = 0; + + for (;;) + { + outputLength += 12; + writeBuffer_.addMessage(12); + + unsigned char *nextDest = outputMessage + 12 + + (numArcs * 12); + numArcs++; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyArcCacheX[index], 8); + value += lastX; + PutUINT(value, nextDest, bigEndian_); + lastX = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyArcCacheY[index], 8); + value += lastY; + PutUINT(value, nextDest, bigEndian_); + lastY = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyArcCacheWidth[index], 8); + value += lastWidth; + PutUINT(value, nextDest, bigEndian_); + lastWidth = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyArcCacheHeight[index], 8); + value += lastHeight; + PutUINT(value, nextDest, bigEndian_); + lastHeight = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyArcCacheAngle1[index], 8); + value += lastAngle1; + PutUINT(value, nextDest, bigEndian_); + lastAngle1 = value; + nextDest += 2; + + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyArcCacheAngle2[index], 8); + value += lastAngle2; + PutUINT(value, nextDest, bigEndian_); + lastAngle2 = value; + nextDest += 2; + + if (++index == 2) index = 0; + + decodeBuffer.decodeBoolValue(value); + + if (!value) break; + } + writeBuffer_.unregisterPointer(); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_PolyPoint: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyPoint); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + unsigned int numPoints; + decodeBuffer.decodeValue(numPoints, 16, 4); + outputLength = (numPoints << 2) + 12; + outputMessage = writeBuffer_.addMessage(outputLength); + unsigned int relativeCoordMode; + decodeBuffer.decodeBoolValue(relativeCoordMode); + outputMessage[1] = (unsigned char) relativeCoordMode; + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0; + + for (unsigned int i = 0; i < numPoints; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyPointCacheX[index], 8); + lastX += value; + PutUINT(lastX, nextDest, bigEndian_); + nextDest += 2; + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyPointCacheY[index], 8); + lastY += value; + PutUINT(lastY, nextDest, bigEndian_); + nextDest += 2; + + if (++index == 2) index = 0; + } + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_PolyLine: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolyLine); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + unsigned int numPoints; + decodeBuffer.decodeValue(numPoints, 16, 4); + outputLength = (numPoints << 2) + 12; + outputMessage = writeBuffer_.addMessage(outputLength); + unsigned int relativeCoordMode; + decodeBuffer.decodeBoolValue(relativeCoordMode); + outputMessage[1] = (unsigned char) relativeCoordMode; + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + + unsigned int index = 0; + unsigned int lastX = 0, lastY = 0; + + for (unsigned int i = 0; i < numPoints; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyLineCacheX[index], 8); + lastX += value; + PutUINT(lastX, nextDest, bigEndian_); + nextDest += 2; + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyLineCacheY[index], 8); + lastY += value; + PutUINT(lastY, nextDest, bigEndian_); + nextDest += 2; + + if (++index == 2) index = 0; + } + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_PolyRectangle: + { + unsigned int numRectangles; + decodeBuffer.decodeValue(numRectangles, 16, 3); + outputLength = (numRectangles << 3) + 12; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + for (unsigned int i = 0; i < numRectangles; i++) + for (unsigned int k = 0; k < 4; k++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> polyRectangleGeomCache[k], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + } + break; + case X_PolySegment: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PolySegment); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + unsigned int numSegments; + decodeBuffer.decodeValue(numSegments, 16, 4); + outputLength = (numSegments << 3) + 12; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 8, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + + for (numSegments *= 2; numSegments; numSegments--) + { + unsigned int index; + decodeBuffer.decodeBoolValue(index); + unsigned int x; + decodeBuffer.decodeCachedValue(x, 16, + clientCache_ -> polySegmentCacheX, 6); + x += clientCache_ -> polySegmentLastX[index]; + PutUINT(x, nextDest, bigEndian_); + nextDest += 2; + + unsigned int y; + decodeBuffer.decodeCachedValue(y, 16, + clientCache_ -> polySegmentCacheY, 6); + y += clientCache_ -> polySegmentLastY[index]; + PutUINT(y, nextDest, bigEndian_); + nextDest += 2; + + clientCache_ -> polySegmentLastX[clientCache_ -> polySegmentCacheIndex] = x; + clientCache_ -> polySegmentLastY[clientCache_ -> polySegmentCacheIndex] = y; + + if (clientCache_ -> polySegmentCacheIndex == 1) + clientCache_ -> polySegmentCacheIndex = 0; + else + clientCache_ -> polySegmentCacheIndex = 1; + } + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_PutImage: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_PutImage); + + hit = handleDecode(decodeBuffer, clientCache_, messageStore, + outputOpcode, outputMessage, outputLength); + + if (outputOpcode == X_PutImage) + { + handleImage(outputOpcode, outputMessage, outputLength); + } + } + break; + case X_QueryBestSize: + { + outputLength = 12; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 2); + outputMessage[1] = (unsigned char)value; + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeValue(value, 16, 8); + PutUINT(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeValue(value, 16, 8); + PutUINT(value, outputMessage + 10, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_QueryColors: + { + // Differential or plain data compression? + decodeBuffer.decodeBoolValue(value); + + if (value) + { + unsigned int numColors; + decodeBuffer.decodeValue(numColors, 16, 5); + outputLength = (numColors << 2) + 8; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> colormapCache); + PutULONG(value, outputMessage + 4, bigEndian_); + unsigned char *nextDest = outputMessage + 8; + unsigned int predictedPixel = clientCache_ -> queryColorsLastPixel; + for (unsigned int i = 0; i < numColors; i++) + { + unsigned int pixel; + decodeBuffer.decodeBoolValue(value); + if (value) + pixel = predictedPixel; + else + decodeBuffer.decodeValue(pixel, 32, 9); + PutULONG(pixel, nextDest, bigEndian_); + if (i == 0) + clientCache_ -> queryColorsLastPixel = pixel; + predictedPixel = pixel + 1; + nextDest += 4; + } + } + else + { + // Request length. + unsigned int requestLength; + decodeBuffer.decodeValue(requestLength, 16, 10); + outputLength = (requestLength << 2); + outputMessage = writeBuffer_.addMessage(outputLength); + + const unsigned char *compressedData = NULL; + unsigned int compressedDataSize = 0; + + int decompressed = handleDecompress(decodeBuffer, outputOpcode, 4, + outputMessage, outputLength, compressedData, + compressedDataSize); + if (decompressed < 0) + { + return -1; + } + } + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_QueryExtension: + { + unsigned int nameLength; + decodeBuffer.decodeValue(nameLength, 16, 6); + outputLength = 8 + RoundUp4(nameLength); + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(nameLength, outputMessage + 4, bigEndian_); + unsigned char *nextDest = outputMessage + 8; + for (unsigned int i = 0; i < nameLength; i++) + { + decodeBuffer.decodeValue(value, 8); + *nextDest++ = (unsigned char) value; + } + + unsigned int hide = 0; + + #ifdef HIDE_MIT_SHM_EXTENSION + + if (!strncmp((char *) outputMessage + 8, "MIT-SHM", 7)) + { + #ifdef TEST + *logofs << "handleWrite: Going to hide MIT-SHM extension in reply.\n" + << logofs_flush; + #endif + + hide = 1; + } + + #endif + + #ifdef HIDE_BIG_REQUESTS_EXTENSION + + if (!strncmp((char *) outputMessage + 8, "BIG-REQUESTS", 12)) + { + #ifdef TEST + *logofs << "handleWrite: Going to hide BIG-REQUESTS extension in reply.\n" + << logofs_flush; + #endif + + hide = 1; + } + + #endif + + #ifdef HIDE_XKEYBOARD_EXTENSION + + else if (!strncmp((char *) outputMessage + 8, "XKEYBOARD", 9)) + { + #ifdef TEST + *logofs << "handleWrite: Going to hide XKEYBOARD extension in reply.\n" + << logofs_flush; + #endif + + hide = 1; + } + + #endif + + #ifdef HIDE_XFree86_Bigfont_EXTENSION + + else if (!strncmp((char *) outputMessage + 8, "XFree86-Bigfont", 15)) + { + #ifdef TEST + *logofs << "handleWrite: Going to hide XFree86-Bigfont extension in reply.\n" + << logofs_flush; + #endif + + hide = 1; + } + + #endif + + // + // This is if you want to experiment disabling SHAPE extensions. + // + + #ifdef HIDE_SHAPE_EXTENSION + + if (!strncmp((char *) outputMessage + 8, "SHAPE", 5)) + { + #ifdef DEBUG + *logofs << "handleWrite: Going to hide SHAPE extension in reply.\n" + << logofs_flush; + #endif + + hide = 1; + } + + #endif + + // + // Check if user disabled RENDER extension. + // + + if (control -> HideRender == 1 && + strncmp((char *) outputMessage + 8, "RENDER", 6) == 0) + { + #ifdef TEST + *logofs << "handleWrite: Going to hide RENDER extension in reply.\n" + << logofs_flush; + #endif + + hide = 1; + } + + unsigned int extension = 0; + + if (strncmp((char *) outputMessage + 8, "SHAPE", 5) == 0) + { + extension = X_NXInternalShapeExtension; + } + else if (strncmp((char *) outputMessage + 8, "RENDER", 6) == 0) + { + extension = X_NXInternalRenderExtension; + } + + sequenceQueue_.push(clientSequence_, outputOpcode, + outputOpcode, hide, extension); + } + break; + case X_QueryFont: + { + outputLength = 8; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 29, 5); + clientCache_ -> lastFont += value; + clientCache_ -> lastFont &= 0x1fffffff; + PutULONG(clientCache_ -> lastFont, outputMessage + 4, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_SetClipRectangles: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_SetClipRectangles); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + break; + } + + unsigned int numRectangles; + + // Since ProtoStep9 (#issue 108) + decodeBuffer.decodeValue(numRectangles, 15, 4); + + outputLength = (numRectangles << 3) + 12; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeValue(value, 2); + outputMessage[1] = (unsigned char) value; + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> setClipRectanglesXCache, 8); + PutUINT(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> setClipRectanglesYCache, 8); + PutUINT(value, outputMessage + 10, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + for (unsigned int i = 0; i < numRectangles; i++) + { + for (unsigned int k = 0; k < 4; k++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache_ -> setClipRectanglesGeomCache[k], 8); + PutUINT(value, nextDest, bigEndian_); + nextDest += 2; + } + } + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_SetDashes: + { + unsigned int numDashes; + decodeBuffer.decodeCachedValue(numDashes, 16, + clientCache_ -> setDashesLengthCache, 5); + outputLength = 12 + RoundUp4(numDashes); + outputMessage = writeBuffer_.addMessage(outputLength); + PutUINT(numDashes, outputMessage + 10, bigEndian_); + decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> setDashesOffsetCache, 5); + PutUINT(value, outputMessage + 8, bigEndian_); + unsigned char *nextDest = outputMessage + 12; + for (unsigned int i = 0; i < numDashes; i++) + { + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache_ -> setDashesDashCache_[i & 1], 5); + *nextDest++ = cValue; + } + } + break; + case X_SetSelectionOwner: + { + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> setSelectionOwnerCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> getSelectionOwnerSelectionCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 32, + clientCache_ -> setSelectionOwnerTimestampCache, 9); + PutULONG(value, outputMessage + 12, bigEndian_); + } + break; + case X_TranslateCoords: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_TranslateCoords); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + sequenceQueue_.push(clientSequence_, outputOpcode); + + break; + } + + outputLength = 16; + outputMessage = writeBuffer_.addMessage(outputLength); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> translateCoordsSrcCache, 9); + PutULONG(value, outputMessage + 4, bigEndian_); + decodeBuffer.decodeCachedValue(value, 29, + clientCache_ -> translateCoordsDstCache, 9); + PutULONG(value, outputMessage + 8, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> translateCoordsXCache, 8); + PutUINT(value, outputMessage + 12, bigEndian_); + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> translateCoordsYCache, 8); + PutUINT(value, outputMessage + 14, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_GetImage: + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_GetImage); + + if (handleDecodeCached(decodeBuffer, clientCache_, messageStore, + outputMessage, outputLength)) + { + sequenceQueue_.push(clientSequence_, outputOpcode); + + break; + } + + outputLength = 20; + outputMessage = writeBuffer_.addMessage(outputLength); + // Format. + unsigned int format; + decodeBuffer.decodeValue(format, 2); + outputMessage[1] = (unsigned char) format; + // Drawable. + decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache); + PutULONG(value, outputMessage + 4, bigEndian_); + // X. + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> putImageXCache, 8); + clientCache_ -> putImageLastX += value; + clientCache_ -> putImageLastX &= 0xffff; + PutUINT(clientCache_ -> putImageLastX, outputMessage + 8, bigEndian_); + // Y. + decodeBuffer.decodeCachedValue(value, 16, + clientCache_ -> putImageYCache, 8); + clientCache_ -> putImageLastY += value; + clientCache_ -> putImageLastY &= 0xffff; + PutUINT(clientCache_ -> putImageLastY, outputMessage + 10, bigEndian_); + // Width. + unsigned int width; + decodeBuffer.decodeCachedValue(width, 16, + clientCache_ -> putImageWidthCache, 8); + PutUINT(width, outputMessage + 12, bigEndian_); + // Height. + unsigned int height; + decodeBuffer.decodeCachedValue(height, 16, + clientCache_ -> putImageHeightCache, 8); + PutUINT(height, outputMessage + 14, bigEndian_); + // Plane mask. + decodeBuffer.decodeCachedValue(value, 32, + clientCache_ -> getImagePlaneMaskCache, 5); + PutULONG(value, outputMessage + 16, bigEndian_); + + sequenceQueue_.push(clientSequence_, outputOpcode); + + handleSave(messageStore, outputMessage, outputLength); + } + break; + case X_GetPointerMapping: + { + outputLength = 4; + outputMessage = writeBuffer_.addMessage(outputLength); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + case X_GetKeyboardControl: + { + outputLength = 4; + outputMessage = writeBuffer_.addMessage(outputLength); + + sequenceQueue_.push(clientSequence_, outputOpcode); + } + break; + default: + { + if (outputOpcode == opcodeStore_ -> renderExtension) + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXInternalRenderExtension); + + hit = handleDecode(decodeBuffer, clientCache_, messageStore, + outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> shapeExtension) + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXInternalShapeExtension); + + hit = handleDecode(decodeBuffer, clientCache_, messageStore, + outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> putPackedImage) + { + #ifdef DEBUG + *logofs << "handleWrite: Decoding packed image request for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXPutPackedImage); + + hit = handleDecode(decodeBuffer, clientCache_, messageStore, + outputOpcode, outputMessage, outputLength); + + if (outputOpcode == opcodeStore_ -> putPackedImage) + { + handleImage(outputOpcode, outputMessage, outputLength); + } + } + else if (outputOpcode == opcodeStore_ -> setUnpackColormap) + { + #ifdef DEBUG + *logofs << "handleWrite: Decoding set unpack colormap request " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXSetUnpackColormap); + + hit = handleDecode(decodeBuffer, clientCache_, messageStore, + outputOpcode, outputMessage, outputLength); + // + // Message could have been split. + // + + if (outputOpcode == opcodeStore_ -> setUnpackColormap) + { + handleColormap(outputOpcode, outputMessage, outputLength); + } + } + else if (outputOpcode == opcodeStore_ -> setUnpackAlpha) + { + #ifdef DEBUG + *logofs << "handleWrite: Decoding unpack alpha request for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXSetUnpackAlpha); + + hit = handleDecode(decodeBuffer, clientCache_, messageStore, + outputOpcode, outputMessage, outputLength); + // + // Message could have been split. + // + + if (outputOpcode == opcodeStore_ -> setUnpackAlpha) + { + handleAlpha(outputOpcode, outputMessage, outputLength); + } + } + else if (outputOpcode == opcodeStore_ -> setUnpackGeometry) + { + #ifdef DEBUG + *logofs << "handleWrite: Decoding set unpack geometry request " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXSetUnpackGeometry); + + hit = handleDecode(decodeBuffer, clientCache_, messageStore, + outputOpcode, outputMessage, outputLength); + + handleGeometry(outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> startSplit) + { + handleStartSplitRequest(decodeBuffer, outputOpcode, + outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> endSplit) + { + handleEndSplitRequest(decodeBuffer, outputOpcode, + outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> commitSplit) + { + int result = handleCommitSplitRequest(decodeBuffer, outputOpcode, + outputMessage, outputLength); + + // + // Check if message has been successfully + // extracted from the split store. In this + // case post-process it in the usual way. + // + + if (result > 0) + { + if (outputOpcode == opcodeStore_ -> putPackedImage || + outputOpcode == X_PutImage) + { + handleImage(outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> setUnpackColormap) + { + handleColormap(outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> setUnpackAlpha) + { + handleAlpha(outputOpcode, outputMessage, outputLength); + } + } + else if (result < 0) + { + return -1; + } + } + else if (outputOpcode == opcodeStore_ -> abortSplit) + { + handleAbortSplitRequest(decodeBuffer, outputOpcode, + outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> finishSplit) + { + #ifdef DEBUG + *logofs << "handleWrite: Decoding finish split request " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache_ -> resourceCache); + + handleNullRequest(outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> freeSplit) + { + #ifdef DEBUG + *logofs << "handleWrite: Decoding free split request " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache_ -> resourceCache); + + handleNullRequest(outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> freeUnpack) + { + #ifdef DEBUG + *logofs << "handleWrite: Decoding free unpack request " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache_ -> resourceCache); + + #ifdef DEBUG + *logofs << "handleWrite: Freeing unpack state for resource " + << (unsigned int) cValue << ".\n" << logofs_flush; + #endif + + handleUnpackStateRemove(cValue); + + handleNullRequest(outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> setExposeParameters) + { + // + // Send expose events according to agent's wish. + // + + decodeBuffer.decodeBoolValue(enableExpose_); + decodeBuffer.decodeBoolValue(enableGraphicsExpose_); + decodeBuffer.decodeBoolValue(enableNoExpose_); + + handleNullRequest(outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> getUnpackParameters) + { + // + // Client proxy needs the list of supported + // unpack methods. We would need an encode + // buffer, but this is in proxy, not here in + // channel. + // + + #ifdef TEST + *logofs << "handleWrite: Sending X_GetInputFocus request for FD#" + << fd_ << " due to OPCODE#" << (unsigned int) outputOpcode + << ".\n" << logofs_flush; + #endif + + outputOpcode = X_GetInputFocus; + + outputLength = 4; + outputMessage = writeBuffer_.addMessage(outputLength); + + sequenceQueue_.push(clientSequence_, outputOpcode, + opcodeStore_ -> getUnpackParameters); + } + else if (outputOpcode == opcodeStore_ -> getControlParameters || + outputOpcode == opcodeStore_ -> getCleanupParameters || + outputOpcode == opcodeStore_ -> getImageParameters) + { + handleNullRequest(outputOpcode, outputMessage, outputLength); + } + else if (outputOpcode == opcodeStore_ -> getShmemParameters) + { + if (handleShmemRequest(decodeBuffer, outputOpcode, + outputMessage, outputLength) < 0) + { + return -1; + } + } + else if (outputOpcode == opcodeStore_ -> setCacheParameters) + { + if (handleCacheRequest(decodeBuffer, outputOpcode, + outputMessage, outputLength) < 0) + { + return -1; + } + } + else if (outputOpcode == opcodeStore_ -> getFontParameters) + { + if (handleFontRequest(decodeBuffer, outputOpcode, + outputMessage, outputLength) < 0) + { + return -1; + } + } + else + { + MessageStore *messageStore = clientStore_ -> + getRequestStore(X_NXInternalGenericRequest); + + hit = handleDecode(decodeBuffer, clientCache_, messageStore, + outputOpcode, outputMessage, outputLength); + } + } + } // End of switch on opcode. + + // + // TODO: at the moment the variable hit was being set + // but not used, so to avoid the corresponding warning + // this logging block has been added. + // This code will probably be optimized away when none + // of the defines is set, but if there is no additional + // use for the hit variable in the future, then maybe + // it could be removed completely. + // + + if (hit) + { + #if defined(TEST) || defined(OPCODES) + *logofs << "handleWrite: Cached flag enabled in handled request.\n" + << logofs_flush; + #endif + } + + // + // A packed image request can generate more than just + // a single X_PutImage. Write buffer is handled inside + // handleUnpack(). Cannot simply assume that the final + // opcode and size must be put at the buffer offset as + // as buffer could have been grown or could have been + // replaced by a scratch buffer. The same is true in + // the case of a shared memory image. + // + + if (outputOpcode != 0) + { + // + // Commit opcode and size to the buffer. + // + + *outputMessage = (unsigned char) outputOpcode; + + PutUINT(outputLength >> 2, outputMessage + 2, bigEndian_); + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleWrite: Handled request OPCODE#" + << (unsigned int) outputOpcode << " (" + << DumpOpcode(outputOpcode) << ") for FD#" + << fd_ << " sequence " << clientSequence_ + << ". " << outputLength << " bytes out.\n" + << logofs_flush; + #endif + } + #if defined(TEST) || defined(OPCODES) + else + { + // + // In case of shared memory images the log doesn't + // reflect the actual opcode of the request that is + // going to be written. It would be possible to find + // the opcode of the original request received from + // the remote proxy in member imageState_ -> opcode, + // but we have probably already deleted the struct. + // + + *logofs << "handleWrite: Handled image request for FD#" + << fd_ << " new sequence " << clientSequence_ + << ". " << outputLength << " bytes out.\n" + << logofs_flush; + } + #endif + + // + // Check if we produced enough data. We need to + // decode all the proxy messages or the decode + // buffer will be left in an inconsistent state, + // so we just update the finish flag in case of + // failure. + // + + handleFlush(flush_if_needed); + + } // End of while (decodeBuffer.decodeOpcodeValue(outputOpcode, 8, ... + + } // End of the decoding block. + + // + // Write any remaining data to the X connection. + // + + if (handleFlush(flush_if_any) < 0) + { + return -1; + } + + // + // Reset offset at which we read the + // last event looking for the shared + // memory completion. + // + + if (shmemState_ != NULL) + { + shmemState_ -> checked = 0; + } + + return 1; +} + +// +// End of handleWrite(). +// + +// +// Other members. +// + +int ServerChannel::handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, + T_store_action action, int position, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + // Since ProtoStep7 (#issue 108) + splitState_.current = splitState_.resource; + + handleSplitStoreAlloc(&splitResources_, splitState_.current); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Message OPCODE#" + << (unsigned int) store -> opcode() << " of size " << size + << " [split] with resource " << splitState_.current + << " position " << position << " and action [" + << DumpAction(action) << "] at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + // + // Get the MD5 of the message being + // split. + // + + T_checksum checksum = NULL; + + if (action != IS_HIT) + { + handleSplitChecksum(decodeBuffer, checksum); + } + + // + // The method must abort the connection + // if it can't allocate the split. + // + + Split *splitMessage = clientStore_ -> getSplitStore(splitState_.current) -> + add(store, splitState_.current, position, + action, checksum, buffer, size); + + // + // If the encoding side didn't provide + // a checksum, then don't send the split + // report. + // + + if (checksum == NULL) + { + if (action == IS_HIT) + { + splitMessage -> setState(split_loaded); + } + else + { + splitMessage -> setState(split_missed); + } + + #if defined(TEST) || defined(SPLIT) + + *logofs << "handleSplit: SPLIT! There are " << clientStore_ -> + getSplitTotalSize() << " messages and " << clientStore_ -> + getSplitTotalStorageSize() << " bytes to send in " + << "the split stores.\n" << logofs_flush; + + clientStore_ -> dumpSplitStore(splitState_.current); + + #endif + + return 1; + } + + delete [] checksum; + + // + // Tell the split store if it must use + // the disk cache to retrieve and save + // the message. + // + + splitMessage -> setPolicy(splitState_.load, splitState_.save); + + // + // Try to locate the message on disk. + // + + if (clientStore_ -> getSplitStore(splitState_.current) -> + load(splitMessage) == 1) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Loaded the message " + << "from the image cache.\n" << logofs_flush; + #endif + + splitMessage -> setState(split_loaded); + } + else + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: WARNING! SPLIT! Can't find the message " + << "in the image cache.\n" << logofs_flush; + #endif + + splitMessage -> setState(split_missed); + } + + #if defined(TEST) || defined(SPLIT) + + T_timestamp startTs = getTimestamp(); + + *logofs << "handleSplit: SPLIT! Encoding abort " + << "split events for FD#" << fd_ << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + + if (proxy -> handleAsyncSplit(fd_, splitMessage) < 0) + { + return -1; + } + + // + // Send the encoded data immediately. We + // want the abort split message to reach + // the remote proxy as soon as possible. + // + + if (proxy -> handleAsyncFlush() < 0) + { + return -1; + } + + #if defined(TEST) || defined(SPLIT) + + *logofs << "handleSplit: SPLIT! Spent " + << diffTimestamp(startTs, getTimestamp()) << " Ms " + << "handling abort split events for FD#" << fd_ + << ".\n" << logofs_flush; + + *logofs << "handleSplit: SPLIT! There are " << clientStore_ -> + getSplitTotalSize() << " messages and " << clientStore_ -> + getSplitTotalStorageSize() << " bytes to send in " + << "the split stores.\n" << logofs_flush; + + clientStore_ -> dumpSplitStore(splitState_.current); + + #endif + + return 1; +} + +int ServerChannel::handleSplit(DecodeBuffer &decodeBuffer) +{ + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Going to handle splits " + << "for FD#" << fd_ << " at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + unsigned char resource; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeCachedValue(resource, 8, + clientCache_ -> resourceCache); + + splitState_.current = resource; + + handleSplitStoreAlloc(&splitResources_, splitState_.current); + + SplitStore *splitStore = clientStore_ -> getSplitStore(splitState_.current); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Handling splits for " + << "resource [" << splitState_.current << "] with " + << splitStore -> getSize() << " elements " + << "in the split store.\n" << logofs_flush; + #endif + + int result = splitStore -> receive(decodeBuffer); + + if (result < 0) + { + #ifdef PANIC + *logofs << "handleSplit: PANIC! Receive of split for FD#" << fd_ + << " failed.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Receive of split for FD#" << fd_ + << " failed.\n"; + + return -1; + } + else if (result == 0) + { + // + // The split is still incomplete. It's time + // to check if we need to start the house- + // keeping process to take care of the image + // cache. + // + + if (proxy -> handleAsyncKeeperCallback() < 0) + { + return -1; + } + } + else + { + // + // Note that we don't need the resource id at the + // X server side and, thus, we don't provide it + // at the time we add split to the split store. + // + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Remote agent should " + << "now commit a new split for resource [" + << splitState_.current << "].\n" + << logofs_flush; + + clientStore_ -> dumpCommitStore(); + + #endif + + if (splitStore -> getSize() == 0) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! Removing split store " + << "for resource [" << splitState_.current + << "] at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + handleSplitStoreRemove(&splitResources_, splitState_.current); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: SPLIT! There are [" << clientStore_ -> + getSplitTotalSize() << "] messages and " << clientStore_ -> + getSplitTotalStorageSize() << " bytes to send in " + << "the split stores.\n" << logofs_flush; + #endif + } + else + { + // + // If the next split is discarded, it can be + // that, since the beginning of the split, we + // have saved the message on the disk, due to + // a more recent split operation. This is also + // the case when we had to discard the message + // because it was locked but, since then, we + // completed the transferral of the split. + // + + Split *splitMessage = splitStore -> getFirstSplit(); + + if (splitMessage -> getAction() == is_discarded && + splitMessage -> getState() == split_missed && + splitStore -> load(splitMessage) == 1) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplit: WARNING! SPLIT! Asynchronously " + << "loaded the message from the image cache.\n" + << logofs_flush; + #endif + + splitMessage -> setState(split_loaded); + + #if defined(TEST) || defined(SPLIT) + + T_timestamp startTs = getTimestamp(); + + *logofs << "handleSplit: WARNING! SPLIT! Asynchronously " + << "encoding abort split events for FD#" << fd_ + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + if (proxy -> handleAsyncSplit(fd_, splitMessage) < 0) + { + return -1; + } + + // + // Send the encoded data immediately. We + // want the abort split message to reach + // the remote proxy as soon as possible. + // + + if (proxy -> handleAsyncFlush() < 0) + { + return -1; + } + + #if defined(TEST) || defined(SPLIT) + + *logofs << "handleSplit: WARNING! SPLIT! Spent " + << diffTimestamp(startTs, getTimestamp()) << " Ms " + << "handling asynchronous abort split events for " + << "FD#" << fd_ << ".\n" << logofs_flush; + + *logofs << "handleSplit: SPLIT! There are " << clientStore_ -> + getSplitTotalSize() << " messages and " << clientStore_ -> + getSplitTotalStorageSize() << " bytes to send in " + << "the split stores.\n" << logofs_flush; + + clientStore_ -> dumpSplitStore(splitState_.current); + + #endif + } + } + } + + return 1; +} + +int ServerChannel::handleSplitEvent(EncodeBuffer &encodeBuffer, Split *splitMessage) +{ + int resource = splitMessage -> getResource(); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitEvent: SPLIT! Going to send a " + << "split report for resource " << resource + << ".\n" << logofs_flush; + #endif + + // + // This function is called only after the message + // has been searched in the disk cache. We need to + // inform the other side if the data transfer can + // start or it must be aborted to let the local + // side use the copy that was found on the disk. + // + + #if defined(TEST) || defined(INFO) + + if (splitMessage -> getState() != split_loaded && + splitMessage -> getState() != split_missed) + { + *logofs << "handleSplitEvent: PANIC! Can't find the split to be aborted.\n" + << logofs_flush; + + HandleCleanup(); + } + + #endif + + // + // We need to send a boolean telling if the split + // was found or not, followed by the checksum of + // message we are referencing. + // + + T_checksum checksum = splitMessage -> getChecksum(); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitEvent: SPLIT! Sending split report for " + << "checksum [" << DumpChecksum(checksum) << "].\n" + << logofs_flush; + #endif + + if (proxy -> handleAsyncSwitch(fd_) < 0) + { + return -1; + } + + encodeBuffer.encodeOpcodeValue(opcodeStore_ -> splitEvent, + serverCache_ -> opcodeCache); + + // + // The encoding in older protocol versions + // is different but we will never try to + // send a split report if the remote does + // not support our version. + // + + encodeBuffer.encodeCachedValue(resource, 8, + serverCache_ -> resourceCache); + + if (splitMessage -> getState() == split_loaded) + { + encodeBuffer.encodeBoolValue(1); + + encodeBuffer.encodeOpcodeValue(splitMessage -> getStore() -> opcode(), + serverCache_ -> abortOpcodeCache); + + encodeBuffer.encodeValue(splitMessage -> compressedSize(), 32, 14); + } + else + { + encodeBuffer.encodeBoolValue(0); + } + + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + encodeBuffer.encodeValue((unsigned int) checksum[i], 8); + } + + // + // Update statistics for this special opcode. + // + + int bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) || defined(INFO) || defined(SPLIT) + *logofs << "handleSplitEvent: SPLIT! Handled event OPCODE#" + << (unsigned int) opcodeStore_ -> splitEvent << " (" + << DumpOpcode(opcodeStore_ -> splitEvent) << ")" << " for FD#" + << fd_ << " sequence none. 0 bytes in, " << bits << " bits (" + << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush; + #endif + + statistics -> addEventBits(opcodeStore_ -> splitEvent, 0, bits); + + return 1; +} + +int ServerChannel::handleAbortSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + unsigned char resource; + + decodeBuffer.decodeCachedValue(resource, 8, + clientCache_ -> resourceCache); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleAbortSplitRequest: SPLIT! Handling abort split " + << "request for FD#" << fd_ << " and resource " + << (unsigned) resource << ".\n" + << logofs_flush; + #endif + + int splits = 0; + + SplitStore *splitStore = clientStore_ -> getSplitStore(resource); + + if (splitStore != NULL) + { + // + // Discard from the memory cache the messages + // that are still incomplete and then get rid + // of the splits in the store. + // + + #if defined(TEST) || defined(SPLIT) + + clientStore_ -> dumpSplitStore(resource); + + #endif + + Split *splitMessage; + + for (;;) + { + splitMessage = splitStore -> getFirstSplit(); + + if (splitMessage == NULL) + { + // + // Check if we had created the store + // but no message was added yet. + // + + #ifdef WARNING + + if (splits == 0) + { + *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The " + << "split store for resource [" << (unsigned int) + resource << "] is unexpectedly empty.\n" + << logofs_flush; + } + + #endif + + break; + } + + // + // Splits already aborted can't be in the + // split store. + // + + #if defined(TEST) || defined(SPLIT) + + if (splitMessage -> getState() == split_aborted) + { + *logofs << "handleAbortSplitRequest: PANIC! SPLIT! Found an " + << "aborted split in store [" << (unsigned int) resource + << "].\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + if (splitMessage -> getAction() == IS_HIT) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleAbortSplitRequest: SPLIT! Removing the " + << "split from the memory cache.\n" + << logofs_flush; + #endif + + splitMessage -> getStore() -> remove(splitMessage -> getPosition(), + discard_checksum, use_data); + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleAbortSplitRequest: SPLIT! Removing the " + << "split from the split store.\n" + << logofs_flush; + #endif + + splitMessage = splitStore -> pop(); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleAbortSplitRequest: SPLIT! Freeing up the " + << "aborted split.\n" << logofs_flush; + #endif + + delete splitMessage; + + splits++; + } + } + #ifdef WARNING + else + { + *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The " + << "split store for resource [" << (unsigned int) + resource << "] is already empty.\n" + << logofs_flush; + } + #endif + + handleNullRequest(opcode, buffer, size); + + return (splits > 0); +} + +int ServerChannel::handleCommitSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + // + // Get request type and position of the image + // to commit. + // + + unsigned char request; + + decodeBuffer.decodeOpcodeValue(request, clientCache_ -> opcodeCache); + + unsigned int diffCommit; + + decodeBuffer.decodeValue(diffCommit, 32, 5); + + splitState_.commit += diffCommit; + + unsigned char resource = 0; + unsigned int commit = 1; + + // + // Send the resource id and the commit flag. + // The resource id is ignored at the moment. + // The message will be handled based on the + // resource id that was sent together with + // the original message. + // + + decodeBuffer.decodeCachedValue(resource, 8, + clientCache_ -> resourceCache); + + decodeBuffer.decodeBoolValue(commit); + + Split *split = handleSplitCommitRemove(request, resource, splitState_.commit); + + if (split == NULL) + { + return -1; + } + + clientStore_ -> getCommitStore() -> update(split); + + if (commit == 1) + { + #if defined(TEST) || defined(SPLIT) + *logofs << "handleCommitSplitRequest: SPLIT! Handling split commit " + << "for FD#" << fd_ << " with commit " << commit + << " request " << (unsigned) request << " resource " + << (unsigned) resource << " and position " + << splitState_.commit << ".\n" + << logofs_flush; + #endif + + // + // Allocate as many bytes in the write + // buffer as the final length of the + // message in uncompressed form. + // + + size = split -> plainSize(); + + buffer = writeBuffer_.addMessage(size); + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleCommitSplitRequest: SPLIT! Prepared an " + << "outgoing buffer of " << size << " bytes.\n" + << logofs_flush; + #endif + + if (clientStore_ -> getCommitStore() -> expand(split, buffer, size) < 0) + { + writeBuffer_.removeMessage(size); + + commit = 0; + } + } + + // + // Free the split. + // + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleCommitSplitRequest: SPLIT! Freeing up the " + << "committed split.\n" << logofs_flush; + #endif + + delete split; + + // + // Discard the operation and send a null + // message. + // + + if (commit == 0) + { + handleNullRequest(opcode, buffer, size); + } + else + { + // + // Save the sequence number to be able + // to mask any error generated by the + // request. + // + + updateCommitQueue(clientSequence_); + + // + // Now in the write buffer there is + // a copy of this request. + // + + opcode = request; + } + + return commit; +} + +int ServerChannel::handleGeometry(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size) +{ + // + // Replace the old geometry and taint + // the message into a X_NoOperation. + // + + int resource = *(buffer + 1); + + #ifdef TEST + *logofs << "handleGeometry: Setting new unpack geometry " + << "for resource " << resource << ".\n" + << logofs_flush; + #endif + + handleUnpackStateInit(resource); + + handleUnpackAllocGeometry(resource); + + unpackState_[resource] -> geometry -> depth1_bpp = *(buffer + 4); + unpackState_[resource] -> geometry -> depth4_bpp = *(buffer + 5); + unpackState_[resource] -> geometry -> depth8_bpp = *(buffer + 6); + unpackState_[resource] -> geometry -> depth16_bpp = *(buffer + 7); + unpackState_[resource] -> geometry -> depth24_bpp = *(buffer + 8); + unpackState_[resource] -> geometry -> depth32_bpp = *(buffer + 9); + + unpackState_[resource] -> geometry -> red_mask = GetULONG(buffer + 12, bigEndian_); + unpackState_[resource] -> geometry -> green_mask = GetULONG(buffer + 16, bigEndian_); + unpackState_[resource] -> geometry -> blue_mask = GetULONG(buffer + 20, bigEndian_); + + handleCleanAndNullRequest(opcode, buffer, size); + + return 1; +} + +int ServerChannel::handleColormap(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size) +{ + // + // Replace the old colormap and taint + // the message into a X_NoOperation. + // + + int resource = *(buffer + 1); + + #ifdef TEST + *logofs << "handleColormap: Setting new unpack colormap " + << "for resource " << resource << ".\n" + << logofs_flush; + #endif + + handleUnpackStateInit(resource); + + handleUnpackAllocColormap(resource); + + // + // New protocol versions send the alpha + // data in compressed form. + // + + // + // Since ProtoStep7 (#issue 108) + // + + { // An anonymous block is used here to limit the scope of local variables + unsigned int packed = GetULONG(buffer + 8, bigEndian_); + unsigned int unpacked = GetULONG(buffer + 12, bigEndian_); + + validateSize("colormap", packed, unpacked, 16, size); + + if (unpackState_[resource] -> colormap -> entries != unpacked >> 2 && + unpackState_[resource] -> colormap -> data != NULL) + { + #ifdef TEST + *logofs << "handleColormap: Freeing previously allocated " + << "unpack colormap data.\n" << logofs_flush; + #endif + + delete [] unpackState_[resource] -> colormap -> data; + + unpackState_[resource] -> colormap -> data = NULL; + unpackState_[resource] -> colormap -> entries = 0; + } + + #ifdef TEST + *logofs << "handleColormap: Setting " << unpacked + << " bytes of unpack colormap data for resource " + << resource << ".\n" << logofs_flush; + #endif + + if (unpackState_[resource] -> colormap -> data == NULL) + { + unpackState_[resource] -> colormap -> data = + (unsigned int *) new unsigned char[unpacked]; + + if (unpackState_[resource] -> colormap -> data == NULL) + { + #ifdef PANIC + *logofs << "handleColormap: PANIC! Can't allocate " + << unpacked << " entries for unpack colormap data " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + goto handleColormapEnd; + } + + #ifdef DEBUG + *logofs << "handleColormap: Size of new colormap data is " + << unpacked << ".\n" << logofs_flush; + #endif + } + + unsigned int method = *(buffer + 4); + + if (method == PACK_COLORMAP) + { + if (UnpackColormap(method, buffer + 16, packed, + (unsigned char *) unpackState_[resource] -> + colormap -> data, unpacked) < 0) + { + #ifdef PANIC + *logofs << "handleColormap: PANIC! Can't unpack " << packed + << " bytes to " << unpacked << " entries for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + delete [] unpackState_[resource] -> colormap -> data; + + unpackState_[resource] -> colormap -> data = NULL; + unpackState_[resource] -> colormap -> entries = 0; + + goto handleColormapEnd; + } + } + else + { + memcpy((unsigned char *) unpackState_[resource] -> + colormap -> data, buffer + 16, unpacked); + } + + unpackState_[resource] -> colormap -> entries = unpacked >> 2; + + #if defined(DEBUG) && defined(DUMP) + + *logofs << "handleColormap: Dumping colormap entries:\n" + << logofs_flush; + + const unsigned char *p = (const unsigned char *) unpackState_[resource] -> colormap -> data; + + for (unsigned int i = 0; i < unpackState_[resource] -> + colormap -> entries; i++) + { + *logofs << "handleColormap: [" << i << "] [" + << (void *) ((int) p[i]) << "].\n" + << logofs_flush; + } + + #endif + } // end anonymous block + +handleColormapEnd: + + handleCleanAndNullRequest(opcode, buffer, size); + + return 1; +} + +int ServerChannel::handleAlpha(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size) +{ + int resource = *(buffer + 1); + + #ifdef TEST + *logofs << "handleAlpha: Setting new unpack alpha " + << "for resource " << resource << ".\n" + << logofs_flush; + #endif + + handleUnpackStateInit(resource); + + handleUnpackAllocAlpha(resource); + + // + // New protocol versions send the alpha + // data in compressed form. + // + + // + // Since ProtoStep7 (#issue 108) + // + + { // An anonymous block is used here to limit the scope of local variables + unsigned int packed = GetULONG(buffer + 8, bigEndian_); + unsigned int unpacked = GetULONG(buffer + 12, bigEndian_); + + validateSize("alpha", packed, unpacked, 16, size); + + if (unpackState_[resource] -> alpha -> entries != unpacked && + unpackState_[resource] -> alpha -> data != NULL) + { + #ifdef TEST + *logofs << "handleAlpha: Freeing previously allocated " + << "unpack alpha data.\n" << logofs_flush; + #endif + + delete [] unpackState_[resource] -> alpha -> data; + + unpackState_[resource] -> alpha -> data = NULL; + unpackState_[resource] -> alpha -> entries = 0; + } + + #ifdef TEST + *logofs << "handleAlpha: Setting " << unpacked + << " bytes of unpack alpha data for resource " + << resource << ".\n" << logofs_flush; + #endif + + if (unpackState_[resource] -> alpha -> data == NULL) + { + unpackState_[resource] -> alpha -> data = new unsigned char[unpacked]; + + if (unpackState_[resource] -> alpha -> data == NULL) + { + #ifdef PANIC + *logofs << "handleAlpha: PANIC! Can't allocate " + << unpacked << " entries for unpack alpha data " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + goto handleAlphaEnd; + } + + #ifdef DEBUG + *logofs << "handleAlpha: Size of new alpha data is " + << unpacked << ".\n" << logofs_flush; + #endif + } + + unsigned int method = *(buffer + 4); + + if (method == PACK_ALPHA) + { + if (UnpackAlpha(method, buffer + 16, packed, + unpackState_[resource] -> alpha -> + data, unpacked) < 0) + { + #ifdef PANIC + *logofs << "handleAlpha: PANIC! Can't unpack " << packed + << " bytes to " << unpacked << " entries for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + delete [] unpackState_[resource] -> alpha -> data; + + unpackState_[resource] -> alpha -> data = NULL; + unpackState_[resource] -> alpha -> entries = 0; + + goto handleAlphaEnd; + } + } + else + { + memcpy((unsigned char *) unpackState_[resource] -> + alpha -> data, buffer + 16, unpacked); + } + + unpackState_[resource] -> alpha -> entries = unpacked; + + #if defined(DEBUG) && defined(DUMP) + + *logofs << "handleAlpha: Dumping alpha entries:\n" + << logofs_flush; + + const unsigned char *p = unpackState_[resource] -> alpha -> data; + + for (unsigned int i = 0; i < unpackState_[resource] -> + alpha -> entries; i++) + { + *logofs << "handleAlpha: [" << i << "] [" + << (void *) ((int) p[i]) << "].\n" + << logofs_flush; + } + + #endif + } //end anonymous block + +handleAlphaEnd: + + handleCleanAndNullRequest(opcode, buffer, size); + + return 1; +} + +int ServerChannel::handleImage(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size) +{ + int result = 1; + + // + // Save the original opcode together with + // the image state so we can later find if + // this is a plain or a packed image when + // moving data to the shared memory area. + // + + handleImageStateAlloc(opcode); + + if (opcode == opcodeStore_ -> putPackedImage) + { + // + // Unpack the image and put a X_PutImage in a + // new buffer. Save the expected output size, + // so, in the case of a decoding error we can + // still update the statistics. + // + + int length = GetULONG(buffer + 20, bigEndian_); + + #ifdef TEST + *logofs << "handleImage: Sending image for FD#" << fd_ + << " due to OPCODE#" << (unsigned int) opcode << " with " + << GetULONG(buffer + 16, bigEndian_) << " bytes packed " + << "and " << GetULONG(buffer + 20, bigEndian_) + << " bytes unpacked.\n" << logofs_flush; + #endif + + statistics -> addPackedBytesIn(size); + + result = handleUnpack(opcode, buffer, size); + + if (result < 0) + { + // + // Recover from the error. Send a X_NoOperation + // to keep the sequence counter in sync with + // the remote peer. + // + + size = 4; + buffer = writeBuffer_.addMessage(size); + + *buffer = X_NoOperation; + + PutUINT(size >> 2, buffer + 2, bigEndian_); + + #ifdef PANIC + *logofs << "handleImage: PANIC! Sending X_NoOperation for FD#" + << fd_ << " to recover from failed unpack.\n" + << logofs_flush; + #endif + + // + // Set the output length to reflect the amount of + // data that would have been produced by unpacking + // the image. This is advisable to keep the count- + // ers in sync with those at remote proxy. Setting + // the size here doesn't have any effect on the + // size of data sent to the X server as the actual + // size will be taken from the content of the write + // buffer. + // + + size = length; + } + + statistics -> addPackedBytesOut(size); + + // + // Refrain the write loop from putting + // opcode and size in the output buffer. + // + + opcode = 0; + } + + // + // Now image is unpacked as a X_PutImage + // in write buffer. Check if we can send + // the image using the MIT-SHM extension. + // + + if (result > 0) + { + result = handleShmem(opcode, buffer, size); + + // + // We already put opcode and size in + // the resulting buffer. + // + + if (result > 0) + { + opcode = 0; + } + } + + return 1; +} + +int ServerChannel::handleMotion(EncodeBuffer &encodeBuffer) +{ + #if defined(TEST) || defined(INFO) + + if (lastMotion_[0] == '\0') + { + *logofs << "handleMotion: PANIC! No motion events to send " + << "for FD#" << fd_ << ".\n" << logofs_flush; + + HandleCleanup(); + } + + #endif + + #if defined(TEST) || defined(INFO) + *logofs << "handleMotion: Sending motion events for FD#" + << fd_ << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + // + // Replicate code from read loop. When have + // time and wish, try to split everything + // in functions. + // + + if (proxy -> handleAsyncSwitch(fd_) < 0) + { + return -1; + } + + const unsigned char *buffer = lastMotion_; + unsigned char opcode = *lastMotion_; + unsigned int size = 32; + + if (GetUINT(buffer + 2, bigEndian_) < serverSequence_) + { + PutUINT(serverSequence_, (unsigned char *) buffer + 2, bigEndian_); + } + + encodeBuffer.encodeOpcodeValue(opcode, serverCache_ -> opcodeCache); + + unsigned int sequenceNum = GetUINT(buffer + 2, bigEndian_); + + unsigned int sequenceDiff = sequenceNum - serverSequence_; + + serverSequence_ = sequenceNum; + + #ifdef DEBUG + *logofs << "handleMotion: Last server sequence number for FD#" + << fd_ << " is " << serverSequence_ << " with " + << "difference " << sequenceDiff << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(sequenceDiff, 16, + serverCache_ -> eventSequenceCache, 7); + + // + // If we fast encoded the message + // then skip the rest. + // + + if (control -> LocalDeltaCompression == 0) + { + int result = handleFastReadEvent(encodeBuffer, opcode, + buffer, size); + + #ifdef DEBUG + *logofs << "handleMotion: Sent saved motion event for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + lastMotion_[0] = '\0'; + + #ifdef DEBUG + *logofs << "handleMotion: Reset last motion event for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + if (result < 0) + { + return -1; + } + else if (result > 0) + { + return 1; + } + } + + // + // This should be just the part specific + // for motion events but is currently a + // copy-paste of code from the read loop. + // + + unsigned char detail = buffer[1]; + if (*buffer == MotionNotify) + encodeBuffer.encodeBoolValue((unsigned int) detail); + else if ((*buffer == EnterNotify) || (*buffer == LeaveNotify)) + encodeBuffer.encodeValue((unsigned int) detail, 3); + else if (*buffer == KeyRelease) + { + if (detail == serverCache_ -> keyPressLastKey) + encodeBuffer.encodeBoolValue(1); + else + { + encodeBuffer.encodeBoolValue(0); + encodeBuffer.encodeValue((unsigned int) detail, 8); + } + } + else if ((*buffer == ButtonPress) || (*buffer == ButtonRelease)) + encodeBuffer.encodeCachedValue(detail, 8, + serverCache_ -> buttonCache); + else + encodeBuffer.encodeValue((unsigned int) detail, 8); + unsigned int timestamp = GetULONG(buffer + 4, bigEndian_); + unsigned int timestampDiff = timestamp - serverCache_ -> lastTimestamp; + serverCache_ -> lastTimestamp = timestamp; + encodeBuffer.encodeCachedValue(timestampDiff, 32, + serverCache_ -> motionNotifyTimestampCache, 9); + int skipRest = 0; + if (*buffer == KeyRelease) + { + skipRest = 1; + for (unsigned int i = 8; i < 31; i++) + { + if (buffer[i] != serverCache_ -> keyPressCache[i - 8]) + { + skipRest = 0; + break; + } + } + encodeBuffer.encodeBoolValue(skipRest); + } + if (!skipRest) + { + const unsigned char *nextSrc = buffer + 8; + for (unsigned int i = 0; i < 3; i++) + { + encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29, + *serverCache_ -> motionNotifyWindowCache[i], 6); + nextSrc += 4; + } + unsigned int rootX = GetUINT(buffer + 20, bigEndian_); + unsigned int rootY = GetUINT(buffer + 22, bigEndian_); + unsigned int eventX = GetUINT(buffer + 24, bigEndian_); + unsigned int eventY = GetUINT(buffer + 26, bigEndian_); + eventX -= rootX; + eventY -= rootY; + encodeBuffer.encodeCachedValue(rootX - + serverCache_ -> motionNotifyLastRootX, 16, + serverCache_ -> motionNotifyRootXCache, 6); + serverCache_ -> motionNotifyLastRootX = rootX; + encodeBuffer.encodeCachedValue(rootY - + serverCache_ -> motionNotifyLastRootY, 16, + serverCache_ -> motionNotifyRootYCache, 6); + serverCache_ -> motionNotifyLastRootY = rootY; + encodeBuffer.encodeCachedValue(eventX, 16, + serverCache_ -> motionNotifyEventXCache, 6); + encodeBuffer.encodeCachedValue(eventY, 16, + serverCache_ -> motionNotifyEventYCache, 6); + encodeBuffer.encodeCachedValue(GetUINT(buffer + 28, bigEndian_), + 16, serverCache_ -> motionNotifyStateCache); + if ((*buffer == EnterNotify) || (*buffer == LeaveNotify)) + encodeBuffer.encodeValue((unsigned int) buffer[30], 2); + else + encodeBuffer.encodeBoolValue((unsigned int) buffer[30]); + if ((*buffer == EnterNotify) || (*buffer == LeaveNotify)) + encodeBuffer.encodeValue((unsigned int) buffer[31], 2); + else if (*buffer == KeyPress) + { + serverCache_ -> keyPressLastKey = detail; + for (unsigned int i = 8; i < 31; i++) + { + serverCache_ -> keyPressCache[i - 8] = buffer[i]; + } + } + } + + // + // Print info about achieved compression + // and update the statistics. + // + + int bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleMotion: Handled event OPCODE#" << (unsigned int) buffer[0] + << " for FD#" << fd_ << " sequence " << sequenceNum << ". " + << size << " bytes in, " << bits << " bits (" << ((float) bits) / 8 + << " bytes) out.\n" << logofs_flush; + #endif + + statistics -> addEventBits(*buffer, size << 3, bits); + + #ifdef DEBUG + *logofs << "handleMotion: Sent saved motion event for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + lastMotion_[0] = '\0'; + + #ifdef DEBUG + *logofs << "handleMotion: Reset last motion event for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + return 1; +} + +int ServerChannel::handleConfiguration() +{ + #ifdef TEST + *logofs << "ServerChannel: Setting new buffer parameters " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + readBuffer_.setSize(control -> ServerInitialReadSize, + control -> ServerMaximumBufferSize); + + writeBuffer_.setSize(control -> TransportXBufferSize, + control -> TransportXBufferThreshold, + control -> TransportMaximumBufferSize); + + transport_ -> setSize(control -> TransportXBufferSize, + control -> TransportXBufferThreshold, + control -> TransportMaximumBufferSize); + return 1; +} + +int ServerChannel::handleFinish() +{ + #ifdef TEST + *logofs << "ServerChannel: Finishing connection for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + congestion_ = 0; + priority_ = 0; + + finish_ = 1; + + // + // Reset the motion event. + // + + lastMotion_[0] = '\0'; + + transport_ -> fullReset(); + + return 1; +} + +int ServerChannel::handleAsyncEvents() +{ + // + // Encode more events while decoding the + // proxy messages. + // + + if (transport_ -> readable() > 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleAsyncEvents: WARNING! Encoding events " + << "for FD#" << fd_ << " at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + #if defined(TEST) || defined(INFO) + + T_timestamp startTs = getTimestamp(); + + #endif + + if (proxy -> handleAsyncRead(fd_) < 0) + { + return -1; + } + + #if defined(TEST) || defined(INFO) + *logofs << "handleAsyncEvents: Spent " << diffTimestamp(startTs, + getTimestamp()) << " Ms handling events for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + return 1; + } + + return 0; +} + +int ServerChannel::handleUnpack(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size) +{ + int resource = *(buffer + 1); + + #ifdef DEBUG + *logofs << "handleUnpack: Unpacking image for resource " << resource + << " with method " << (unsigned int) *(buffer + 12) + << ".\n" << logofs_flush; + #endif + + handleUnpackStateInit(resource); + + T_geometry *geometryState = unpackState_[resource] -> geometry; + T_colormap *colormapState = unpackState_[resource] -> colormap; + T_alpha *alphaState = unpackState_[resource] -> alpha; + + if (geometryState == NULL) + { + #ifdef PANIC + *logofs << "handleUnpack: PANIC! Missing geometry unpacking " + << "image for resource " << resource << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Missing geometry unpacking " + << "image for resource " << resource << ".\n"; + + return -1; + } + + // + // Get the image data from the buffer. + // + + imageState_ -> drawable = GetULONG(buffer + 4, bigEndian_); + imageState_ -> gcontext = GetULONG(buffer + 8, bigEndian_); + + imageState_ -> method = *(buffer + 12); + + imageState_ -> format = *(buffer + 13); + imageState_ -> srcDepth = *(buffer + 14); + imageState_ -> dstDepth = *(buffer + 15); + + imageState_ -> srcLength = GetULONG(buffer + 16, bigEndian_); + imageState_ -> dstLength = GetULONG(buffer + 20, bigEndian_); + + imageState_ -> srcX = GetUINT(buffer + 24, bigEndian_); + imageState_ -> srcY = GetUINT(buffer + 26, bigEndian_); + imageState_ -> srcWidth = GetUINT(buffer + 28, bigEndian_); + imageState_ -> srcHeight = GetUINT(buffer + 30, bigEndian_); + + imageState_ -> dstX = GetUINT(buffer + 32, bigEndian_); + imageState_ -> dstY = GetUINT(buffer + 34, bigEndian_); + imageState_ -> dstWidth = GetUINT(buffer + 36, bigEndian_); + imageState_ -> dstHeight = GetUINT(buffer + 38, bigEndian_); + + #ifdef TEST + *logofs << "handleUnpack: Source X is " << imageState_ -> srcX + << " Y is " << imageState_ -> srcY << " width is " + << imageState_ -> srcWidth << " height is " + << imageState_ -> srcHeight << ".\n" + << logofs_flush; + #endif + + #ifdef TEST + *logofs << "handleUnpack: Destination X is " << imageState_ -> dstX + << " Y is " << imageState_ -> dstY << " width is " + << imageState_ -> dstWidth << " height is " + << imageState_ -> dstHeight << ".\n" + << logofs_flush; + #endif + + if (imageState_ -> srcX != 0 || imageState_ -> srcY != 0) + { + #ifdef PANIC + *logofs << "handleUnpack: PANIC! Unsupported source coordinates " + << "in unpack request.\n" << logofs_flush; + #endif + + return -1; + } + else if (imageState_ -> method == PACK_COLORMAP_256_COLORS && + (colormapState == NULL || colormapState -> data == NULL)) + { + #ifdef PANIC + *logofs << "handleUnpack: PANIC! Cannot find any unpack colormap.\n" + << logofs_flush; + #endif + + return -1; + } + + // + // Field srcLength carries size of image data in + // packed format. Field dstLength is size of the + // image in the original X bitmap format. + // + + unsigned int srcDataOffset = 40; + + unsigned int srcSize = imageState_ -> srcLength; + + unsigned int removeSize = size; + + unsigned char *srcData = buffer + srcDataOffset; + + // + // Get source and destination bits per pixel. + // + + int srcBitsPerPixel = MethodBitsPerPixel(imageState_ -> method); + + if (srcBitsPerPixel <= 0) + { + #ifdef PANIC + *logofs << "handleUnpack: PANIC! Can't identify source " + << "bits per pixel for method " << (unsigned int) + imageState_ -> method << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify source bits " + << "per pixel for method " << (unsigned int) + imageState_ -> method << ".\n"; + + writeBuffer_.removeMessage(removeSize); + + return -1; + } + + #ifdef TEST + *logofs << "handleUnpack: Source bits per pixel are " + << srcBitsPerPixel << " source data size is " + << srcSize << ".\n" << logofs_flush; + #endif + + int dstBitsPerPixel = UnpackBitsPerPixel(geometryState, imageState_ -> dstDepth); + + if (dstBitsPerPixel <= 0) + { + #ifdef PANIC + *logofs << "handleUnpack: PANIC! Can't identify " + << "destination bits per pixel for depth " + << (unsigned int) imageState_ -> dstDepth + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't identify " + << "destination bits per pixel for depth " + << (unsigned int) imageState_ -> dstDepth + << ".\n"; + + writeBuffer_.removeMessage(removeSize); + + return -1; + } + + // + // Destination is a PutImage request. + // + + unsigned int dstDataOffset = 24; + + // + // Output buffer size must match the number of input + // pixels multiplied by the number of bytes per pixel + // of current geometry. + // + + size = (RoundUp4(imageState_ -> dstWidth * dstBitsPerPixel / 8) * + imageState_ -> dstHeight) + dstDataOffset; + + #ifdef TEST + *logofs << "handleUnpack: Destination bits per pixel are " + << dstBitsPerPixel << " destination data size is " + << size - dstDataOffset << ".\n" << logofs_flush; + #endif + + unsigned int dstSize = size - dstDataOffset; + + imageState_ -> dstLines = imageState_ -> dstHeight; + + unsigned char *dstData; + + // + // Size of the final output buffer had to be stored + // in the offset field of XImage/NXPackedImage. + // + + #ifdef WARNING + + if (dstSize != imageState_ -> dstLength) + { + *logofs << "handleUnpack: WARNING! Destination size mismatch " + << "with reported " << imageState_ -> dstLength + << " and actual " << dstSize << ".\n" + << logofs_flush; + } + + #endif + + // + // The decoding algorithm has put the packed image + // in the plain write buffer. Let's use the scratch + // buffer to uncompress the image. + // + + buffer = writeBuffer_.addScratchMessage(size); + + dstData = buffer + dstDataOffset; + + // + // Unpack image into the buffer. + // + + *buffer = (unsigned char) X_PutImage; + + *(buffer + 1) = imageState_ -> format; + + PutUINT(size >> 2, buffer + 2, bigEndian_); + + PutULONG(imageState_ -> drawable, buffer + 4, bigEndian_); + PutULONG(imageState_ -> gcontext, buffer + 8, bigEndian_); + + PutUINT(imageState_ -> dstWidth, buffer + 12, bigEndian_); + PutUINT(imageState_ -> dstLines, buffer + 14, bigEndian_); + + PutUINT(imageState_ -> dstX, buffer + 16, bigEndian_); + PutUINT(imageState_ -> dstY, buffer + 18, bigEndian_); + + *(buffer + 20) = 0; + *(buffer + 21) = imageState_ -> dstDepth; + + #ifdef TEST + *logofs << "handleUnpack: Write buffer size is " + << writeBuffer_.getLength() << " scratch size is " + << writeBuffer_.getScratchLength() << ".\n" + << logofs_flush; + #endif + + int result = 0; + + switch (imageState_ -> method) + { + case PACK_JPEG_8_COLORS: + case PACK_JPEG_64_COLORS: + case PACK_JPEG_256_COLORS: + case PACK_JPEG_512_COLORS: + case PACK_JPEG_4K_COLORS: + case PACK_JPEG_32K_COLORS: + case PACK_JPEG_64K_COLORS: + case PACK_JPEG_256K_COLORS: + case PACK_JPEG_2M_COLORS: + case PACK_JPEG_16M_COLORS: + { + result = UnpackJpeg(geometryState, imageState_ -> method, srcData, + srcSize, dstBitsPerPixel, imageState_ -> dstWidth, + imageState_ -> dstHeight, dstData, dstSize); + break; + } + case PACK_PNG_8_COLORS: + case PACK_PNG_64_COLORS: + case PACK_PNG_256_COLORS: + case PACK_PNG_512_COLORS: + case PACK_PNG_4K_COLORS: + case PACK_PNG_32K_COLORS: + case PACK_PNG_64K_COLORS: + case PACK_PNG_256K_COLORS: + case PACK_PNG_2M_COLORS: + case PACK_PNG_16M_COLORS: + { + result = UnpackPng(geometryState, imageState_ -> method, srcData, + srcSize, dstBitsPerPixel, imageState_ -> dstWidth, + imageState_ -> dstHeight, dstData, dstSize); + break; + } + case PACK_RGB_16M_COLORS: + { + result = UnpackRgb(geometryState, imageState_ -> method, srcData, + srcSize, dstBitsPerPixel, imageState_ -> dstWidth, + imageState_ -> dstHeight, dstData, dstSize); + break; + } + case PACK_RLE_16M_COLORS: + { + result = UnpackRle(geometryState, imageState_ -> method, srcData, + srcSize, dstBitsPerPixel, imageState_ -> dstWidth, + imageState_ -> dstHeight, dstData, dstSize); + break; + } + case PACK_BITMAP_16M_COLORS: + { + result = UnpackBitmap(geometryState, imageState_ -> method, srcData, + srcSize, dstBitsPerPixel, imageState_ -> dstWidth, + imageState_ -> dstHeight, dstData, dstSize); + break; + } + case PACK_COLORMAP_256_COLORS: + { + result = Unpack8(geometryState, colormapState, srcBitsPerPixel, + imageState_ -> srcWidth, imageState_ -> srcHeight, srcData, + srcSize, dstBitsPerPixel, imageState_ -> dstWidth, + imageState_ -> dstHeight, dstData, dstSize); + + break; + } + default: + { + const T_colormask *colorMask = MethodColorMask(imageState_ -> method); + + switch (imageState_ -> method) + { + case PACK_MASKED_8_COLORS: + case PACK_MASKED_64_COLORS: + case PACK_MASKED_256_COLORS: + { + result = Unpack8(geometryState, colorMask, imageState_ -> srcDepth, + imageState_ -> srcWidth, imageState_ -> srcHeight, + srcData, srcSize, imageState_ -> dstDepth, + imageState_ -> dstWidth, imageState_ -> dstHeight, + dstData, dstSize); + break; + } + case PACK_MASKED_512_COLORS: + case PACK_MASKED_4K_COLORS: + case PACK_MASKED_32K_COLORS: + case PACK_MASKED_64K_COLORS: + { + result = Unpack16(geometryState, colorMask, imageState_ -> srcDepth, + imageState_ -> srcWidth, imageState_ -> srcHeight, + srcData, srcSize, imageState_ -> dstDepth, + imageState_ -> dstWidth, imageState_ -> dstHeight, + dstData, dstSize); + break; + } + case PACK_MASKED_256K_COLORS: + case PACK_MASKED_2M_COLORS: + case PACK_MASKED_16M_COLORS: + { + result = Unpack24(geometryState, colorMask, imageState_ -> srcDepth, + imageState_ -> srcWidth, imageState_ -> srcHeight, + srcData, srcSize, imageState_ -> dstDepth, + imageState_ -> dstWidth, imageState_ -> dstHeight, + dstData, dstSize); + break; + } + default: + { + break; + } + } + } + } + + writeBuffer_.removeMessage(removeSize); + + if (result <= 0) + { + #ifdef PANIC + *logofs << "handleUnpack: PANIC! Failed to unpack image " + << "with method '" << (unsigned int) imageState_ -> method + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Failed to unpack image " + << "with method '" << (unsigned int) imageState_ -> method + << "'.\n"; + + // + // TODO: We should mark the image somehow, + // and force the remote to remove it from + // the cache. + // + + writeBuffer_.removeScratchMessage(); + + return -1; + } + + // + // Alpha channel is used only on some 32 bits pixmaps + // and only if render extension is in use. Presently + // we don't have an efficient way to know in advance + // if mask must be applied or not to the image. If an + // alpha channel is set, the function will check if + // the size of the alpha data matches the size of the + // image. In the worst case we'll create an useless + // alpha plane for a pixmap that doesn't need it. + // + + if (alphaState != NULL && alphaState -> data != NULL && + imageState_ -> dstDepth == 32) + { + UnpackAlpha(alphaState, dstData, dstSize, imageByteOrder_); + } + + return 1; +} + +int ServerChannel::handleAuthorization(unsigned char *buffer) +{ + // + // At the present moment we don't support more than + // a single display for each proxy, so authorization + // data is shared among all the channels. + // + // Use the following code to simulate authentication + // failures on a LSB machine: + // + // memcpy(buffer + 12 + (((buffer[6] + 256 * + // buffer[7]) + 3) & ~3), "1234567890123456", 16); + // + + if (auth == NULL) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleAuthorization: Forwarding the real cookie " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + return 0; + } + else if (auth -> checkCookie(buffer) == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleAuthorization: Matched the fake cookie " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + return 1; + } + else + { + #if defined(TEST) || defined(INFO) + *logofs << "handleAuthorization: WARNING! Failed to match " + << "the fake cookie for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + return -1; + } +} + +int ServerChannel::handleAuthorization(const unsigned char *buffer, int size) +{ + // + // Check the X server's response and, in the case of + // an error, print the textual information reported + // by the server. + // + + if (*buffer != 1) + { + const char *reason = NULL; + + // + // At the moment we don't take into account the end- + // ianess of the reply. This should work in any case + // because we simply try to match a few well-known + // error strings. + // + + if (size >= INVALID_COOKIE_SIZE + 8 && + memcmp(buffer + 8, INVALID_COOKIE_DATA, + INVALID_COOKIE_SIZE) == 0) + { + reason = INVALID_COOKIE_DATA; + } + else if (size >= NO_AUTH_PROTO_SIZE + 8 && + memcmp(buffer + 8, NO_AUTH_PROTO_DATA, + NO_AUTH_PROTO_SIZE) == 0) + { + reason = NO_AUTH_PROTO_DATA; + } + else + { + reason = "Unknown"; + } + + #ifdef WARNING + *logofs << "handleAuthorization: WARNING! X connection failed " + << "with error '" << reason << "' on FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + cerr << "Warning" << ": X connection failed " + << "with error '" << reason << "'.\n"; + } + #if defined(TEST) || defined(INFO) + else + { + *logofs << "handleAuthorization: X connection successful " + << "on FD#" << fd_ << ".\n" << logofs_flush; + } + #endif + + return 1; +} + +// +// Use a simple encoding. Need to handle the image +// requests in the usual way and the X_ListExtensions +// and X_QueryExtension to hide MIT-SHM and RENDER +// in the reply. +// + +int ServerChannel::handleFastWriteRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + // + // All the NX requests are handled in the + // main message loop. + // + + // + // Since ProtoStep7 (#issue 108) + // + // The X_PutImage can be handled here only + // if a split was not requested. + // + + if ((opcode >= X_NXFirstOpcode && opcode <= X_NXLastOpcode) || + (opcode == X_PutImage && splitState_.resource != nothing) || + opcode == X_ListExtensions || + opcode == X_QueryExtension) + { + return 0; + } + + #ifdef DEBUG + *logofs << "handleFastWriteRequest: Decoding raw request OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + buffer = writeBuffer_.addMessage(4); + + #ifndef __sun + + unsigned int *next = (unsigned int *) decodeBuffer.decodeMemory(4); + + *((unsigned int *) buffer) = *next; + + #else /* #ifndef __sun */ + + memcpy(buffer, decodeBuffer.decodeMemory(4), 4); + + #endif /* #ifndef __sun */ + + size = GetUINT(buffer + 2, bigEndian_) << 2; + + if (size < 4) + { + #ifdef WARNING + *logofs << "handleFastWriteRequest: WARNING! Assuming size 4 " + << "for suspicious message of size " << size + << ".\n" << logofs_flush; + #endif + + size = 4; + } + + writeBuffer_.registerPointer(&buffer); + + if (writeBuffer_.getAvailable() < size - 4 || + (int) size >= control -> TransportFlushBufferSize) + { + #ifdef DEBUG + *logofs << "handleFastWriteRequest: Using scratch buffer for OPCODE#" + << (unsigned int) opcode << " with size " << size << " and " + << writeBuffer_.getLength() << " bytes in buffer.\n" + << logofs_flush; + #endif + + // + // The procedure moving data to shared memory + // assumes that the full message is stored in + // the scratch buffer. We can safely let the + // scratch buffer inherit the decode buffer + // at the next offset. + // + + writeBuffer_.removeMessage(4); + + buffer = writeBuffer_.addScratchMessage(((unsigned char *) + decodeBuffer.decodeMemory(size - 4)) - 4, size); + } + else + { + writeBuffer_.addMessage(size - 4); + + #ifndef __sun + + if (size <= 32) + { + next = (unsigned int *) decodeBuffer.decodeMemory(size - 4); + + for (unsigned int i = 4; i < size; i += sizeof(unsigned int)) + { + *((unsigned int *) (buffer + i)) = *next++; + } + } + else + { + memcpy(buffer + 4, decodeBuffer.decodeMemory(size - 4), size - 4); + } + + #else /* #ifndef __sun */ + + memcpy(buffer + 4, decodeBuffer.decodeMemory(size - 4), size - 4); + + #endif /* #ifndef __sun */ + } + + // + // Opcode could have been tainted by the client + // proxy. Replace the original opcode with the + // one sent in the decode buffer. + // + + *buffer = opcode; + + writeBuffer_.unregisterPointer(); + + if (opcode == X_PutImage) + { + handleImage(opcode, buffer, size); + } + + #if defined(TEST) || defined(OPCODES) + + if (opcode != 0) + { + *logofs << "handleFastWriteRequest: Handled request " + << "OPCODE#" << (unsigned int) opcode << " (" + << DumpOpcode(opcode) << ") for FD#" << fd_ + << " sequence " << clientSequence_ << ". " + << size << " bytes out.\n" << logofs_flush; + } + else + { + *logofs << "handleFastWriteRequest: Handled image or " + << "other request for FD#" << fd_ + << " sequence " << clientSequence_ << ". " + << size << " bytes out.\n" << logofs_flush; + } + + #endif + + handleFlush(flush_if_needed); + + return 1; +} + +// +// Use the simplest encoding except for replies that +// need to be managed some way. +// + +int ServerChannel::handleFastReadReply(EncodeBuffer &encodeBuffer, const unsigned char &opcode, + const unsigned char *&buffer, const unsigned int &size) +{ + // + // If we pushed a X_GetInputFocus in the sequence + // queue this means that the original message was + // a NX request for which we have to provide a NX + // reply. + // + + if ((opcode >= X_NXFirstOpcode && + opcode <= X_NXLastOpcode) || + opcode == X_QueryExtension || + opcode == X_ListExtensions || + opcode == X_GetInputFocus) + { + return 0; + } + + #ifdef DEBUG + *logofs << "handleFastReadReply: Encoding raw reply OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ + << " with size " << size << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeMemory(buffer, size); + + // + // Send back the reply as soon + // as possible. + // + + priority_++; + + int bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) + *logofs << "handleFastReadReply: Handled raw reply OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ << " sequence " + << serverSequence_ << ". " << size << " bytes in, " + << bits << " bits (" << ((float) bits) / 8 + << " bytes) out.\n" << logofs_flush; + #endif + + statistics -> addReplyBits(opcode, size << 3, bits); + + return 1; +} + +int ServerChannel::handleFastReadEvent(EncodeBuffer &encodeBuffer, const unsigned char &opcode, + const unsigned char *&buffer, const unsigned int &size) +{ + #ifdef DEBUG + *logofs << "handleFastReadEvent: Encoding raw " + << (opcode == X_Error ? "error" : "event") << " OPCODE#" + << (unsigned int) opcode << " for FD#" << fd_ + << " with size " << size << ".\n" + << logofs_flush; + #endif + + encodeBuffer.encodeMemory(buffer, size); + + switch (opcode) + { + case X_Error: + case ButtonPress: + case ButtonRelease: + case KeyPress: + case KeyRelease: + { + priority_++; + } + } + + int bits = encodeBuffer.diffBits(); + + #if defined(TEST) || defined(OPCODES) + + if (opcode == X_Error) + { + unsigned char code = *(buffer + 1); + + *logofs << "handleFastReadEvent: Handled error ERR_CODE#" + << (unsigned int) code << " for FD#" << fd_; + + *logofs << " RES_ID#" << GetULONG(buffer + 4, bigEndian_); + + *logofs << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_); + + *logofs << " MAJ_OP#" << (unsigned int) *(buffer + 10); + + *logofs << " sequence " << serverSequence_ << ". " << size + << " bytes in, " << bits << " bits (" << ((float) bits) / 8 + << " bytes) out.\n" << logofs_flush; + } + else + { + *logofs << "handleFastReadEvent: Handled event OPCODE#" + << (unsigned int) *buffer << " for FD#" << fd_ + << " sequence " << serverSequence_ << ". " << size + << " bytes in, " << bits << " bits (" << ((float) bits) / 8 + << " bytes) out.\n" << logofs_flush; + } + + #endif + + statistics -> addEventBits(opcode, size << 3, bits); + + return 1; +} + +void ServerChannel::initCommitQueue() +{ + #ifdef TEST + *logofs << "initCommitQueue: Resetting the queue of split commits " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + for (int i = 0; i < MAX_COMMIT_SEQUENCE_QUEUE; i++) + { + commitSequenceQueue_[i] = 0; + } +} + +void ServerChannel::updateCommitQueue(unsigned short sequence) +{ + for (int i = 0; i < MAX_COMMIT_SEQUENCE_QUEUE - 1; i++) + { + commitSequenceQueue_[i + 1] = commitSequenceQueue_[i]; + } + + #ifdef TEST + *logofs << "updateCommitQueue: Saved " << sequence + << " as last sequence number of image to commit.\n" + << logofs_flush; + #endif + + commitSequenceQueue_[0] = sequence; +} + +int ServerChannel::checkCommitError(unsigned char error, unsigned short sequence, + const unsigned char *buffer) +{ + // + // Check if error is due to an image commit + // generated at the end of a split. + // + // TODO: It should zero the head of the list + // when an event comes with a sequence number + // greater than the value of the last element + // added. + // + + for (int i = 0; i < MAX_COMMIT_SEQUENCE_QUEUE && + commitSequenceQueue_[i] != 0; i++) + { + #ifdef TEST + *logofs << "checkCommitError: Checking committed image's " + << "sequence number " << commitSequenceQueue_[i] + << " with input sequence " << sequence << ".\n" + << logofs_flush; + #endif + + if (commitSequenceQueue_[i] == sequence) + { + #ifdef WARNING + + *logofs << "checkCommitError: WARNING! Failed operation for " + << "FD#" << fd_ << " with ERR_CODE#" + << (unsigned int) *(buffer + 1); + + *logofs << " RES_ID#" << GetULONG(buffer + 4, bigEndian_); + + *logofs << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_); + + *logofs << " MAJ_OP#" << (unsigned int) *(buffer + 10); + + *logofs << " sequence " << sequence << ".\n"; + + *logofs << logofs_flush; + + #endif + + cerr << "Warning" << ": Failed commit operation " + << "with ERR_CODE#" << (unsigned int) error; + + cerr << " RES_ID#" << GetULONG(buffer + 4, bigEndian_); + + cerr << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_); + + cerr << " MAJ_OP#" << (unsigned int) *(buffer + 10); + + cerr << ".\n"; + + #ifdef WARNING + *logofs << "checkCommitError: WARNING! Suppressing error on " + << "OPCODE#" << (unsigned int) opcodeStore_ -> commitSplit + << " for FD#" << fd_ << " with sequence " << sequence + << " at position " << i << ".\n" << logofs_flush; + #endif + + return 0; + } + } + + return 0; +} + +// +// Check if the user pressed the CTRL+ALT+SHIFT+ESC +// keystroke. At the present moment it uses different +// keycodes based on the client OS. This should be +// implemented in a way that is platform independent +// (that's not an easy task, considered that we don't +// have access to the higher level X libraries). +// + +int ServerChannel::checkKeyboardEvent(unsigned char event, unsigned short sequence, + const unsigned char *buffer) +{ + #ifdef TEST + *logofs << "checkKeyboardEvent: Checking escape sequence with byte [1] " + << (void *) ((unsigned) *(buffer + 1)) << " and bytes [28-29] " + << (void *) ((unsigned) GetUINT(buffer + 28, bigEndian_)) + << " for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + #ifdef __APPLE__ + + int alert = (*(buffer + 1) == 0x3d && + GetUINT(buffer + 28, bigEndian_) == 0x2005); + + #else + + int alert = (*(buffer + 1) == 0x09 && + ((GetUINT(buffer + 28, bigEndian_) & + 0x0d) == 0x0d)); + + #endif + + if (alert == 1) + { + #ifdef PANIC + *logofs << "checkKeyboardEvent: PANIC! Received sequence " + << "CTRL+ALT+SHIFT+ESC " << "for FD#"<< fd_ + << ". Showing the abort dialog.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Received sequence CTRL+ALT+SHIFT+ESC. " + << "Showing the abort dialog.\n"; + + HandleAlert(CLOSE_UNRESPONSIVE_X_SERVER_ALERT, 1); + } + + return alert; +} + +// +// Handle the MIT-SHM initialization +// messages exchanged with the remote +// proxy. +// + +int ServerChannel::handleShmemReply(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned int stage, const unsigned char *buffer, + const unsigned int size) +{ + #ifdef TEST + *logofs << "handleShmemReply: Returning shmem reply for " + << "stage " << stage << ".\n" << logofs_flush; + #endif + + if (opcode == X_QueryExtension) + { + encodeBuffer.encodeValue(stage, 2); + +#ifndef ANDROID + shmemState_ -> present = *(buffer + 8); +#else + shmemState_ -> present = 0; + cerr << "Info: handleShmemReply: In android no shared memory. Setting present to 0 hardcoded\n"; +#endif + shmemState_ -> opcode = *(buffer + 9); + shmemState_ -> event = *(buffer + 10); + shmemState_ -> error = *(buffer + 11); + + #ifdef TEST + *logofs << "handleShmemReply: Extension present is " + << shmemState_ -> present << " with base OPCODE#" + << (unsigned int) shmemState_ -> opcode << " base event " + << (unsigned int) shmemState_ -> event << " base error " + << (unsigned int) shmemState_ -> error << ".\n" + << logofs_flush; + #endif + } + else if (opcode == X_GetInputFocus) + { + encodeBuffer.encodeValue(stage, 2); + + encodeBuffer.encodeBoolValue(0); + + if (shmemState_ -> present == 1 && + shmemState_ -> address != NULL && + shmemState_ -> segment > 0 && + shmemState_ -> id > 0) + { + cerr << "Info" << ": Using shared memory parameters 1/" + << (shmemState_ -> size / 1024) << "K.\n"; + +#ifndef ANDROID + shmemState_ -> enabled = 1; +#else + cerr << "Info: handleShmemReply: In android no shared memory. Setting enabled to -1. This should not be displayed\n"; + shmemState_ -> enabled = -1; +#endif + + encodeBuffer.encodeBoolValue(1); + } + else + { + #ifdef TEST + *logofs << "handleShmemReply: WARNING! Not using shared memory " + << "support in X server for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + cerr << "Info" << ": Using shared memory parameters 0/0K.\n"; + + handleShmemStateRemove(); + + encodeBuffer.encodeBoolValue(0); + } + } + else + { + #ifdef PANIC + *logofs << "handleShmemReply: PANIC! Conversation error " + << "handling shared memory support for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Conversation error handling " + << "shared memory support.\n"; + + return -1; + } + + return 1; +} + +int ServerChannel::handleShmemRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + // + // We need to query and initialize MIT-SHM on + // the real X server. To do this we'll need 3 + // requests. At the end we'll have to encode + // the final reply for the X client side. + // + + handleShmemStateAlloc(); + + unsigned int stage; + + decodeBuffer.decodeValue(stage, 2); + + unsigned int expected = shmemState_ -> stage + 1; + + if (stage != expected || stage > 2) + { + #ifdef PANIC + *logofs << "handleShmemRequest: PANIC! Unexpected stage " + << stage << " in handling shared memory " + << "support for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Unexpected stage " + << stage << " in handling shared memory " + << "support for FD#" << fd_ << ".\n"; + + return -1; + } + + switch (stage) + { + case 0: + { + unsigned int enableClient; + unsigned int enableServer; + + decodeBuffer.decodeBoolValue(enableClient); + decodeBuffer.decodeBoolValue(enableServer); + + unsigned int clientSegment; + unsigned int serverSegment; + + decodeBuffer.decodeValue(clientSegment, 29, 9); + decodeBuffer.decodeValue(serverSegment, 29, 9); + + shmemState_ -> segment = serverSegment; + + #ifdef TEST + *logofs << "handleShmemRequest: Size of the shared memory " + << "segment will be " << control -> ShmemServerSize + << ".\n" << logofs_flush; + #endif + + #ifdef TEST + *logofs << "handleShmemRequest: Sending X_QueryExtension request " + << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int) + opcodeStore_ -> getShmemParameters << " in stage " + << stage << ".\n" << logofs_flush; + #endif + + opcode = X_QueryExtension; + + size = 16; + buffer = writeBuffer_.addMessage(size); + + PutUINT(7, buffer + 4, bigEndian_); + + // + // Simply make the query fail if shared + // memory support is disabled by the + // user. + // +#ifndef ANDROID + if (control -> ShmemServer == 1 && + control -> ShmemServerSize > 0 && + enableServer == 1) + { + memcpy(buffer + 8, "MIT-SHM", 7); + } + else + { + memcpy(buffer + 8, "NO-MIT-", 7); + } +#else + cerr << "Info: handleShmemRequest: In android no shared memory. Returning NO-MIT- answer\n"; + + memcpy(buffer + 8, "NO-MIT-", 7); +#endif + sequenceQueue_.push(clientSequence_, opcode, + opcodeStore_ -> getShmemParameters, stage); + + // + // Save the sequence number so we can + // later identify any matching X error + // received from server. + // + + shmemState_ -> sequence = clientSequence_; + + break; + } + case 1: + { + if (shmemState_ -> present == 1) + { + // + // Make the segment read-write for everybody on + // Cygwin (to avoid any lack of support or any + // performance issue) and on MacOS/X (where the + // 0600 mask doesn't seem to work). + // + + #if defined(__CYGWIN32__) || defined(__APPLE__) + + int permissions = 0777; + + #else + + int permissions = 0600; + + #endif + + shmemState_ -> size = control -> ShmemServerSize; + +#ifndef ANDROID + shmemState_ -> id = shmget(IPC_PRIVATE, shmemState_ -> size, + IPC_CREAT | permissions); +#else + cerr << "Info: handleShmemReqyest: In android no shared memory (shmget). This message should not be displayed present should never be 1 in android\n"; + shmemState_ -> id = -1; +#endif + if (shmemState_ -> id >= 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleShmemRequest: Allocated shared memory " + << "segment of " << shmemState_ -> size + << " bytes with id " << shmemState_ -> id + << ".\n" << logofs_flush; + #endif + + +#ifndef ANDROID + shmemState_ -> address = shmat(shmemState_ -> id, 0, 0); +#else + cerr << "Info: handleShmemReqyest: In android no shared memory (shmat). This message should not be displayed. present should never be 1 in android\n"; + shmemState_ -> address = NULL; +#endif + if (shmemState_ -> address != NULL) + { + #ifdef TEST + *logofs << "handleShmemRequest: Sending X_ShmAttach request " + << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int) + opcodeStore_ -> getShmemParameters << " in stage " + << stage << ".\n" << logofs_flush; + #endif + + opcode = shmemState_ -> opcode; + + size = 16; + buffer = writeBuffer_.addMessage(size); + + *(buffer + 1) = X_ShmAttach; + + PutULONG(shmemState_ -> segment, buffer + 4, bigEndian_); + PutULONG(shmemState_ -> id, buffer + 8, bigEndian_); + + *(buffer + 12) = 1; + + shmemState_ -> sequence = clientSequence_; + + break; + } + else + { + #ifdef WARNING + *logofs << "handleShmemRequest: WARNING! Can't attach the shared " + << "memory segment. Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Can't attach the shared memory " + << "segment. Error is " << EGET() << " '" + << ESTR() << "'.\n"; + } + } + else + { + #ifndef __CYGWIN32__ + + #ifdef WARNING + *logofs << "handleShmemRequest: WARNING! Can't create the shared " + << "memory segment. Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Can't create the shared memory " + << "segment. Error is " << EGET() << " '" + << ESTR() << "'.\n"; + + #else + + #ifdef TEST + *logofs << "handleShmemRequest: WARNING! Can't create the shared " + << "memory segment. Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + #endif + } + } + + if (shmemState_ -> present != 0) + { + #ifdef TEST + *logofs << "handleShmemRequest: Resetting shared memory " + << "presence flag for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + shmemState_ -> present = 0; + } + + handleNullRequest(opcode, buffer, size); + + break; + } + default: + { + #ifdef TEST + *logofs << "handleShmemRequest: Sending X_GetInputFocus request " + << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int) + opcodeStore_ -> getShmemParameters << " in stage " + << stage << ".\n" << logofs_flush; + #endif + + opcode = X_GetInputFocus; + + size = 4; + buffer = writeBuffer_.addMessage(size); + + sequenceQueue_.push(clientSequence_, opcode, + opcodeStore_ -> getShmemParameters, stage); + break; + } + } + + shmemState_ -> stage += 1; + + return 1; +} + +// +// Handling of MIT-SHM extension has been plugged late in +// the design, so we have to make some assumptions. Image +// is a X_PutImage request contained either in the scratch +// buffer or in the normal write buffer. We need to move +// the image data to the shared memory segment and replace +// the X_PutImage request with a X_ShmPutImage. +// + +int ServerChannel::handleShmem(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size) +{ + if (shmemState_ == NULL || shmemState_ -> enabled != 1) + { + #ifdef TEST + + if (shmemState_ != NULL) + { + *logofs << "handleShmem: PANIC! Shared memory " + << "state found but support is not enabled " + << "for FD#" << fd_ << " in stage " + << shmemState_ -> stage << ".\n" + << logofs_flush; + } + + #endif + + return 0; + } +#ifdef ANDROID + cerr << "Info: handleShmem: In android no shared memory. enabled should never be 1. This should not be displayed\n"; + return 0; +#endif + + // + // Ignore null requests and requests that will not result + // in a single X_PutImage. To conform with the other func- + // tions, we get the opcode passed as a parameter. It can + // be zero if we don't want the write loop to put opcode + // and length in the resulting buffer. Anyway we are only + // interested in the original opcode of the request, that + // is stored in the image state. + // + + unsigned char *dstData = buffer + 24; + unsigned int dstDataSize = size - 24; + + if (dstDataSize == 0 || dstDataSize > + (unsigned int) control -> MaximumRequestSize) + { + #ifdef TEST + *logofs << "handleShmem: Ignoring image with opcode " + << (unsigned int) imageState_ -> opcode + << " and size " << size << " for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + return 0; + } + + #ifdef TEST + *logofs << "handleShmem: Handling image with opcode " + << (unsigned int) imageState_ -> opcode + << " and size " << size << " for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + // + // Get image data from buffer. + // + + if (imageState_ -> opcode == X_PutImage) + { + // + // We still need to get the image's data. + // + + imageState_ -> format = *(buffer + 1); + + imageState_ -> drawable = GetULONG(buffer + 4, bigEndian_); + imageState_ -> gcontext = GetULONG(buffer + 8, bigEndian_); + + imageState_ -> dstWidth = GetUINT(buffer + 12, bigEndian_); + imageState_ -> dstHeight = GetUINT(buffer + 14, bigEndian_); + + imageState_ -> srcX = 0; + imageState_ -> srcY = 0; + + imageState_ -> srcWidth = imageState_ -> dstWidth; + imageState_ -> srcHeight = imageState_ -> dstHeight; + + imageState_ -> dstX = GetUINT(buffer + 16, bigEndian_); + imageState_ -> dstY = GetUINT(buffer + 18, bigEndian_); + + imageState_ -> leftPad = *(buffer + 20); + imageState_ -> dstDepth = *(buffer + 21); + + imageState_ -> dstLines = imageState_ -> dstHeight; + + imageState_ -> dstLength = size - 24; + } + + // + // Skip the MIT-SHM operation if the image + // is 1 bits-per-plane. + // + + if (imageState_ -> dstDepth == 1) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleShmem: Ignoring image with opcode " + << (unsigned int) imageState_ -> opcode << " depth " + << (unsigned int) imageState_ -> dstDepth << " and " + << "size " << size << " for FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + return 0; + } + + // + // If the image can't fit in the available + // space, check if the completion event is + // arrived. + // + + #if defined(TEST) || defined(INFO) + + if (isTimestamp(shmemState_ -> last) == 0 && + shmemState_ -> offset != 0) + { + *logofs << "handleShmem: PANIC! No timestamp for sequence " + << shmemState_ -> sequence << " with offset " + << shmemState_ -> offset << ".\n" + << logofs_flush; + } + + #endif + + if (shmemState_ -> offset + imageState_ -> dstLength > + shmemState_ -> size) + { + if (imageState_ -> dstLength > shmemState_ -> size) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleShmem: WARNING! Can't fit the image " + << "in the available memory segment for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + return 0; + } + else if (handleShmemEvent() <= 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleShmem: WARNING! Missing completion " + << "after " << diffTimestamp(shmemState_ -> last, + getTimestamp()) << " Ms for shared memory " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + return 0; + } + } + + // + // Let image start at current offset + // in the shared segment. + // + + #ifdef TEST + *logofs << "handleShmem: Copying " << dstDataSize + << " bytes to shared memory at offset " + << shmemState_ -> offset << " for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + memcpy((unsigned char *) shmemState_ -> address + + shmemState_ -> offset, dstData, dstDataSize); + + // + // Get rid of the original X_PutImage + // request. + // + + if (writeBuffer_.getScratchData() != NULL) + { + writeBuffer_.removeScratchMessage(); + } + else + { + writeBuffer_.removeMessage(size); + } + + // + // Add a X_ShmPutImage request to the + // write buffer. + // + + buffer = writeBuffer_.addMessage(40); + + *buffer = shmemState_ -> opcode; + + *(buffer + 1) = X_ShmPutImage; + + PutUINT(40 >> 2, buffer + 2, bigEndian_); + + PutULONG(imageState_ -> drawable, buffer + 4, bigEndian_); + PutULONG(imageState_ -> gcontext, buffer + 8, bigEndian_); + + PutUINT(imageState_ -> dstWidth, buffer + 12, bigEndian_); + PutUINT(imageState_ -> dstLines, buffer + 14, bigEndian_); + + PutUINT(imageState_ -> srcX, buffer + 16, bigEndian_); + PutUINT(imageState_ -> srcY, buffer + 18, bigEndian_); + + PutUINT(imageState_ -> dstWidth, buffer + 20, bigEndian_); + PutUINT(imageState_ -> dstLines, buffer + 22, bigEndian_); + + PutUINT(imageState_ -> dstX, buffer + 24, bigEndian_); + PutUINT(imageState_ -> dstY, buffer + 26, bigEndian_); + + *(buffer + 28) = imageState_ -> dstDepth; + *(buffer + 29) = imageState_ -> format; + *(buffer + 30) = 1; + + PutULONG(shmemState_ -> segment, buffer + 32, bigEndian_); + PutULONG(shmemState_ -> offset, buffer + 36, bigEndian_); + + shmemState_ -> offset += dstDataSize; + + shmemState_ -> sequence = clientSequence_; + shmemState_ -> last = getTimestamp(); + + #ifdef TEST + *logofs << "handleShmem: Saved shared memory sequence " + << shmemState_ -> sequence << " for FD#" << fd_ + << " with offset " << shmemState_ -> offset + << " at " << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + + // + // Make the X server read immediately + // from the shared memory buffer and + // produce the completion event. + // + + handleFlush(flush_if_any); + + return 1; +} + +// +// Try to read more events from the socket in the +// attempt to get the completion event required +// to reset the MIT-SHM segment. +// + +int ServerChannel::handleShmemEvent() +{ + #if defined(TEST) || defined(INFO) + *logofs << "handleShmemEvent: Waiting for shared memory " + << "sequence " << shmemState_ -> sequence + << " for X server FD#" << fd_ << ".\n" + << logofs_flush; + + T_timestamp startTs = getTimestamp(); + + #endif + + while (isTimestamp(shmemState_ -> last) != 0) + { + if (handleWait(control -> ShmemTimeout) <= 0) + { + break; + } + #if defined(TEST) || defined(INFO) + else + { + *logofs << "handleShmemEvent: WARNING! Encoded events " + << "for FD#" << fd_ << " at " << strMsTimestamp() + << ".\n" << logofs_flush; + } + #endif + } + + if (isTimestamp(shmemState_ -> last) == 0) + { + #if defined(TEST) || defined(INFO) + *logofs << "handleShmemEvent: Spent " + << diffTimestamp(startTs, getTimestamp()) << " Ms " + << "waiting for shared memory sequence for FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + return 1; + } + + #if defined(TEST) || defined(INFO) + *logofs << "handleShmemEvent: WARNING! Can't reset shared " + << "memory sequence for FD#" << fd_ << " after " + << diffTimestamp(shmemState_ -> last, getTimestamp()) + << " Ms.\n" << logofs_flush; + #endif + + return 0; +} + +int ServerChannel::checkShmemEvent(unsigned char event, unsigned short sequence, + const unsigned char *buffer) +{ + if (isTimestamp(shmemState_ -> last) == 1 && + sequence == shmemState_ -> sequence) + { + #ifdef TEST + *logofs << "checkShmemEvent: Reset shared memory sequence " + << shmemState_ -> sequence << " for FD#" << fd_ + << " after " << diffTimestamp(shmemState_ -> last, + getTimestamp()) << " Ms.\n" << logofs_flush; + #endif + + shmemState_ -> sequence = 0; + shmemState_ -> offset = 0; + shmemState_ -> last = nullTimestamp(); + } + #ifdef TEST + else + { + *logofs << "checkShmemEvent: Skipping past shared memory " + << "image sequence " << sequence << " for FD#" + << fd_ << ".\n" << logofs_flush; + } + #endif + + return 1; +} + +int ServerChannel::checkShmemError(unsigned char error, unsigned short sequence, + const unsigned char *buffer) +{ + #ifdef TEST + + *logofs << "checkShmemError: WARNING! Failed operation for " + << "FD#" << fd_ << " in stage " << shmemState_ -> stage + << " with ERR_CODE#" << (unsigned int) *(buffer + 1); + + *logofs << " RES_ID#" << GetULONG(buffer + 4, bigEndian_); + + *logofs << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_); + + *logofs << " MAJ_OP#" << (unsigned int) *(buffer + 10); + + *logofs << " sequence " << sequence << ".\n"; + + *logofs << logofs_flush; + + #endif + + // + // If enabled flag is <= 0 we are still + // in the inizialization phase. In this + // case force presence to false. + // + + if (shmemState_ -> enabled != 1) + { + if (shmemState_ -> present != 0) + { + #ifdef TEST + *logofs << "checkShmemError: Resetting shared memory " + << "presence flag for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + shmemState_ -> present = 0; + } + + return 0; + } + + if (shmemState_ -> sequence == sequence) + { + // + // Reset the sequence and timestamp. + // + + shmemState_ -> sequence = 0; + shmemState_ -> offset = 0; + shmemState_ -> last = nullTimestamp(); + } + + return 1; +} + +int ServerChannel::handleFontRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + // + // Send a synchronization request and use + // the reply to return the requested font + // path. + // + + #ifdef TEST + *logofs << "handleFontRequest: Sending X_GetInputFocus request " + << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int) + opcodeStore_ -> getFontParameters << ".\n" + << logofs_flush; + #endif + + opcode = X_GetInputFocus; + + size = 4; + buffer = writeBuffer_.addMessage(size); + + sequenceQueue_.push(clientSequence_, X_GetInputFocus, + opcodeStore_ -> getFontParameters); + + return 1; +} + +int ServerChannel::handleFontReply(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) +{ + #ifdef TEST + *logofs << "handleFontReply: Encoding font operation " + << "reply with size " << size << ".\n" + << logofs_flush; + #endif + + char data[256]; + + if (fontPort_ != -1) + { + sprintf(data + 1, "tcp/localhost:%d", fontPort_); + } + else + { + *(data + 1) = '\0'; + } + + *data = strlen(data + 1); + + unsigned char *next = (unsigned char *) data; + + unsigned int length = (unsigned int) (*next++); + + encodeBuffer.encodeValue(length, 8); + + encodeBuffer.encodeTextData(next, length); + + return 1; +} + +int ServerChannel::handleCacheRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + unsigned int mask; + + decodeBuffer.decodeCachedValue(mask, 32, clientCache_ -> + setCacheParametersCache); + + splitState_.save = (mask >> 8) & 0xff; + splitState_.load = mask & 0xff; + + #ifdef TEST + *logofs << "handleCacheRequest: Set cache parameters to " + << "save " << splitState_.save << " load " + << splitState_.load << ".\n" << logofs_flush; + #endif + + handleNullRequest(opcode, buffer, size); + + return 1; +} + +int ServerChannel::handleStartSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + // + // Prepare for the split for the selected + // resource. Old proxy versions only used + // the split store at position 0. + // + + // Since ProtoStep7 (#issue 108) + unsigned char resource; + + decodeBuffer.decodeCachedValue(resource, 8, + clientCache_ -> resourceCache); + + splitState_.resource = resource; + + splitState_.current = splitState_.resource; + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleStartSplitRequest: SPLIT! Registered id " + << splitState_.resource << " as resource " + << "waiting for a split.\n" << logofs_flush; + #endif + + handleNullRequest(opcode, buffer, size); + + return 1; +} + +int ServerChannel::handleEndSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size) +{ + // + // Verify that the agent resource matches. + // + + // Since ProtoStep7 (#issue 108) + unsigned char resource; + + decodeBuffer.decodeCachedValue(resource, 8, + clientCache_ -> resourceCache); + + #ifdef TEST + + if (splitState_.resource == nothing) + { + #ifdef PANIC + *logofs << "handleEndSplitRequest: PANIC! SPLIT! Received an end of " + << "split for resource id " << (unsigned int) *(buffer + 1) + << " without a previous start.\n" + << logofs_flush; + #endif + + HandleCleanup(); + } + else if (resource != splitState_.resource) + { + #ifdef PANIC + *logofs << "handleEndSplitRequest: PANIC! SPLIT! Invalid resource id " + << resource << " received while waiting for resource id " + << splitState_.resource << ".\n" << logofs_flush; + #endif + + HandleCleanup(); + } + + #endif + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleEndSplitRequest: SPLIT! Reset id " + << splitState_.resource << " as resource " + << "selected for splits.\n" << logofs_flush; + #endif + + splitState_.resource = nothing; + + handleNullRequest(opcode, buffer, size); + + return 1; +} + +int ServerChannel::handleSplitChecksum(DecodeBuffer &decodeBuffer, T_checksum &checksum) +{ + unsigned int receive; + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeBoolValue(receive); + + if (receive == 1) + { + checksum = new md5_byte_t[MD5_LENGTH]; + + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + decodeBuffer.decodeValue(receive, 8); + + if (checksum != NULL) + { + checksum[i] = (unsigned char) receive; + } + } + + #if defined(TEST) || defined(SPLIT) + *logofs << "handleSplitChecksum: SPLIT! Received checksum " + << "[" << DumpChecksum(checksum) << "].\n" + << logofs_flush; + #endif + + return 1; + } + + return 0; +} + +void ServerChannel::handleShmemStateAlloc() +{ + if (shmemState_ == NULL) + { + shmemState_ = new T_shmem_state(); + + shmemState_ -> stage = -1; + shmemState_ -> present = -1; + shmemState_ -> enabled = -1; + + shmemState_ -> segment = -1; + shmemState_ -> id = -1; + shmemState_ -> address = NULL; + shmemState_ -> size = 0; + + shmemState_ -> opcode = 0xff; + shmemState_ -> event = 0xff; + shmemState_ -> error = 0xff; + + shmemState_ -> sequence = 0; + shmemState_ -> offset = 0; + shmemState_ -> last = nullTimestamp(); + + shmemState_ -> checked = 0; + } +} + +void ServerChannel::handleShmemStateRemove() +{ + if (shmemState_ != NULL) + { + if (shmemState_ -> address != NULL) + { +#ifndef ANDROID + shmdt((char *) shmemState_ -> address); +#else + cerr << "Info: handleShmemStateRemove: In android no shared memory. This should not be displayed. address should always be NULL\n"; +#endif + } + + if (shmemState_ -> id > 0) + { +#ifndef ANDROID + shmctl(shmemState_ -> id, IPC_RMID, 0); +#else + cerr << "Info: handleShmemStateRemove: In android no shared memory. This should not be displayed. id should always be 0\n"; +#endif + } + + delete shmemState_; + + shmemState_ = NULL; + } +} + +void ServerChannel::handleUnpackStateInit(int resource) +{ + if (unpackState_[resource] == NULL) + { + unpackState_[resource] = new T_unpack_state(); + + if (unpackState_[resource] == NULL) + { + #ifdef PANIC + *logofs << "handleUnpackStateInit: PANIC! Can't allocate " + << "memory for unpack state in context [A].\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory for " + << "unpack state in context [A].\n"; + + HandleAbort(); + } + + unpackState_[resource] -> geometry = NULL; + unpackState_[resource] -> colormap = NULL; + unpackState_[resource] -> alpha = NULL; + } +} + +void ServerChannel::handleUnpackAllocGeometry(int resource) +{ + if (unpackState_[resource] -> geometry == NULL) + { + unpackState_[resource] -> geometry = new T_geometry(); + + if (unpackState_[resource] -> geometry == NULL) + { + #ifdef PANIC + *logofs << "handleUnpackAllocGeometry: PANIC! Can't allocate " + << "memory for unpack state in context [B].\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory for " + << "unpack state in context [B].\n"; + + HandleAbort(); + } + + unpackState_[resource] -> geometry -> depth1_bpp = 4; + unpackState_[resource] -> geometry -> depth4_bpp = 4; + unpackState_[resource] -> geometry -> depth8_bpp = 8; + unpackState_[resource] -> geometry -> depth16_bpp = 16; + unpackState_[resource] -> geometry -> depth24_bpp = 32; + unpackState_[resource] -> geometry -> depth32_bpp = 32; + + unpackState_[resource] -> geometry -> red_mask = 0xff0000; + unpackState_[resource] -> geometry -> green_mask = 0x00ff00; + unpackState_[resource] -> geometry -> blue_mask = 0x0000ff; + + unpackState_[resource] -> geometry -> image_byte_order = imageByteOrder_; + unpackState_[resource] -> geometry -> bitmap_bit_order = bitmapBitOrder_; + unpackState_[resource] -> geometry -> scanline_unit = scanlineUnit_; + unpackState_[resource] -> geometry -> scanline_pad = scanlinePad_; + } +} + +void ServerChannel::handleUnpackAllocColormap(int resource) +{ + if (unpackState_[resource] -> colormap == NULL) + { + unpackState_[resource] -> colormap = new T_colormap(); + + if (unpackState_[resource] -> colormap == NULL) + { + #ifdef PANIC + *logofs << "handleUnpackAllocColormap: PANIC! Can't allocate " + << "memory for unpack state in context [C].\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory for " + << "unpack state in context [C].\n"; + + HandleAbort(); + } + + unpackState_[resource] -> colormap -> entries = 0; + unpackState_[resource] -> colormap -> data = NULL; + } +} + +void ServerChannel::handleUnpackAllocAlpha(int resource) +{ + if (unpackState_[resource] -> alpha == NULL) + { + unpackState_[resource] -> alpha = new T_alpha(); + + if (unpackState_[resource] -> alpha == NULL) + { + #ifdef PANIC + *logofs << "handleUnpackAllocAlpha: PANIC! Can't allocate " + << "memory for unpack state in context [D].\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory for " + << "unpack state in context [D].\n"; + + HandleAbort(); + } + + unpackState_[resource] -> alpha -> entries = 0; + unpackState_[resource] -> alpha -> data = NULL; + } +} + +void ServerChannel::handleUnpackStateRemove(int resource) +{ + if (unpackState_[resource] != NULL) + { + delete unpackState_[resource] -> geometry; + + if (unpackState_[resource] -> colormap != NULL) + { + delete [] unpackState_[resource] -> colormap -> data; + } + + delete unpackState_[resource] -> colormap; + + if (unpackState_[resource] -> alpha != NULL) + { + delete [] unpackState_[resource] -> alpha -> data; + } + + delete unpackState_[resource] -> alpha; + + delete unpackState_[resource]; + + unpackState_[resource] = NULL; + } +} + +void ServerChannel::handleEncodeCharInfo(const unsigned char *nextSrc, EncodeBuffer &encodeBuffer) +{ + unsigned int value = GetUINT(nextSrc, bigEndian_) | + (GetUINT(nextSrc + 10, bigEndian_) << 16); + + encodeBuffer.encodeCachedValue(value, 32, + *serverCache_ -> queryFontCharInfoCache[0], 6); + + nextSrc += 2; + + for (unsigned int i = 1; i < 5; i++) + { + unsigned int value = GetUINT(nextSrc, bigEndian_); + + nextSrc += 2; + + encodeBuffer.encodeCachedValue(value, 16, + *serverCache_ -> queryFontCharInfoCache[i], 6); + } +} + +int ServerChannel::setBigEndian(int flag) +{ + bigEndian_ = flag; + + readBuffer_.setBigEndian(flag); + + return 1; +} + +int ServerChannel::setReferences() +{ + #ifdef TEST + *logofs << "ServerChannel: Initializing the static " + << "members for the server channels.\n" + << logofs_flush; + #endif + + #ifdef REFERENCES + + references_ = 0; + + #endif + + return 1; +} diff --git a/nxcomp/src/ServerChannel.h b/nxcomp/src/ServerChannel.h new file mode 100644 index 000000000..374e52896 --- /dev/null +++ b/nxcomp/src/ServerChannel.h @@ -0,0 +1,529 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ServerChannel_H +#define ServerChannel_H + +#include "List.h" +#include "Channel.h" + +#include "SequenceQueue.h" + +#include "ServerReadBuffer.h" + +#include "Unpack.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// How many sequence numbers of split commit +// requests we are going to save in order to +// mask errors. +// + +#define MAX_COMMIT_SEQUENCE_QUEUE 16 + +// +// Define this to know when a channel +// is created or destroyed. +// + +#undef REFERENCES + +// +// This class implements the X server +// side compression of X protocol. +// + +class ServerChannel : public Channel +{ + public: + + ServerChannel(Transport *transport, StaticCompressor *compressor); + + virtual ~ServerChannel(); + + virtual int handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message, + unsigned int length); + + virtual int handleWrite(const unsigned char *message, unsigned int length); + + virtual int handleSplit(EncodeBuffer &encodeBuffer, MessageStore *store, + T_store_action action, int position, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size) + { + return 0; + } + + virtual int handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store, + T_store_action action, int position, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + virtual int handleSplit(EncodeBuffer &encodeBuffer) + { + return 0; + } + + virtual int handleSplit(DecodeBuffer &decodeBuffer); + + virtual int handleSplitEvent(EncodeBuffer &encodeBuffer, Split *split); + + virtual int handleSplitEvent(DecodeBuffer &decodeBuffer) + { + return 0; + } + + // + // Send the last motion notify event + // received from the X server to the + // remote proxy. + // + + virtual int handleMotion(EncodeBuffer &encodeBuffer); + + virtual int handleCompletion(EncodeBuffer &encodeBuffer) + { + return 0; + } + + virtual int handleConfiguration(); + + virtual int handleFinish(); + + virtual int handleAsyncEvents(); + + virtual int needSplit() const + { + return 0; + } + + virtual int needMotion() const + { + return (lastMotion_[0] != '\0'); + } + + virtual T_channel_type getType() const + { + return channel_x11; + } + + int setBigEndian(int flag); + + // + // Initialize the static members. + // + + static int setReferences(); + + private: + + int handleFastReadReply(EncodeBuffer &encodeBuffer, const unsigned char &opcode, + const unsigned char *&buffer, const unsigned int &size); + + int handleFastReadEvent(EncodeBuffer &encodeBuffer, const unsigned char &opcode, + const unsigned char *&buffer, const unsigned int &size); + + int handleFastWriteRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + // + // Handle the fake authorization cookie + // and the X server's reply. + // + + int handleAuthorization(unsigned char *buffer); + int handleAuthorization(const unsigned char *buffer, int size); + + // + // Set the unpack colormap and the alpha + // blending data to be used to unpack + // images. + // + + int handleGeometry(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size); + + int handleColormap(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size); + + int handleAlpha(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size); + + // + // Manage the decoded buffer to unpack + // the image and move the data to the + // shared memory segment. + // + + int handleImage(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size); + + // + // Uncompress a packed image in one + // or more graphic X requests. + // + + int handleUnpack(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size); + + // + // Move the image to the shared + // memory buffer. + // + + int handleShmem(unsigned char &opcode, unsigned char *&buffer, + unsigned int &size); + + // + // Handle suppression of error on + // commit of image splits. + // + + void initCommitQueue(); + + void updateCommitQueue(unsigned short sequence); + + int checkCommitError(unsigned char error, unsigned short sequence, + const unsigned char *buffer); + + void clearCommitQueue() + { + if (commitSequenceQueue_[0] != 0) + { + initCommitQueue(); + } + } + + // + // Check if the user pressed the + // CTRL+ALT+SHIFT+ESC keystroke. + // + + int checkKeyboardEvent(unsigned char event, unsigned short sequence, + const unsigned char *buffer); + + // + // Other utilities. + // + + void handleEncodeCharInfo(const unsigned char *nextSrc, EncodeBuffer &encodeBuffer); + + // + // Handle the MIT-SHM initialization + // messages exchanged with the remote + // proxy. + // + + int handleShmemRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + + int handleShmemReply(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned int stage, const unsigned char *buffer, + const unsigned int size); + + // + // Try to read more events in the attempt to + // get the MIT-SHM image completion event + // from the X server. + // + + int handleShmemEvent(); + + // + // Handle the MIT-SHM events as they are read + // from the socket. + // + + int checkShmemEvent(unsigned char event, unsigned short sequence, + const unsigned char *buffer); + + int checkShmemError(unsigned char error, unsigned short sequence, + const unsigned char *buffer); + + // + // Query the port used to tunnel + // the font server connections. + // + + int handleFontRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + int handleFontReply(EncodeBuffer &encodeBuffer, const unsigned char opcode, + const unsigned char *buffer, const unsigned int size); + + // + // Set the cache policy for image + // requests. + // + + int handleCacheRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + // + // Decode the start and end split + // requests. + // + + int handleStartSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + int handleEndSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + // + // Remove the split store and the + // incomplete messages from the + // memory cache. + // + + int handleAbortSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + // + // Send the split requests to the + // X server once they have been + // recomposed. + // + + int handleCommitSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode, + unsigned char *&buffer, unsigned int &size); + + int handleSplitChecksum(DecodeBuffer &decodeBuffer, T_checksum &checksum); + + // + // Allocate and free the shared memory + // support resources. + // + + void handleShmemStateAlloc(); + void handleShmemStateRemove(); + + // + // Temporary storage for the image info. + // + + void handleImageStateAlloc(unsigned char opcode) + { + if (imageState_ == NULL) + { + imageState_ = new T_image_state(); + } + + imageState_ -> opcode = opcode; + } + + void handleImageStateRemove() + { + if (imageState_ != NULL) + { + delete imageState_; + + imageState_ = NULL; + } + } + + // + // Store the information needed to unpack + // images per each known agent's client. + // + + void handleUnpackStateInit(int resource); + + void handleUnpackAllocGeometry(int resource); + void handleUnpackAllocColormap(int resource); + void handleUnpackAllocAlpha(int resource); + + void handleUnpackStateRemove(int resource); + + typedef struct + { + T_geometry *geometry; + T_colormap *colormap; + T_alpha *alpha; + + } T_unpack_state; + + T_unpack_state *unpackState_[256]; + + // + // Own read buffer. It is able to identify + // full messages read from X descriptor. + // + + ServerReadBuffer readBuffer_; + + // + // Sequence number of last request coming + // from X client or X server. + // + + unsigned int clientSequence_; + unsigned int serverSequence_; + + // + // Used to identify replies based on sequence + // number of original request. + // + + SequenceQueue sequenceQueue_; + + // + // Last motion notify read from the X server. + // + + unsigned char lastMotion_[32]; + + // + // Sequence numbers of last auto-generated + // put image requests. Needed to intercept + // and suppress errors generated by such + // requests. + // + + unsigned int commitSequenceQueue_[MAX_COMMIT_SEQUENCE_QUEUE]; + + // + // Let agent select which expose + // events is going to receive. + // + + unsigned int enableExpose_; + unsigned int enableGraphicsExpose_; + unsigned int enableNoExpose_; + + // + // Used in initialization and handling + // of MIT-SHM shared memory put images. + // + + typedef struct + { + int stage; + int present; + int enabled; + int segment; + int id; + void *address; + unsigned int size; + + unsigned char opcode; + unsigned char event; + unsigned char error; + + unsigned int sequence; + unsigned int offset; + T_timestamp last; + + unsigned int checked; + + } T_shmem_state; + + T_shmem_state *shmemState_; + + // + // Used to pass current image data between + // the different decompression stages. + // + + typedef struct + { + unsigned char opcode; + + unsigned int drawable; + unsigned int gcontext; + + unsigned char method; + + unsigned char format; + unsigned char srcDepth; + unsigned char dstDepth; + + unsigned int srcLength; + unsigned int dstLength; + unsigned int dstLines; + + short int srcX; + short int srcY; + unsigned short srcWidth; + unsigned short srcHeight; + + short int dstX; + short int dstY; + unsigned short dstWidth; + unsigned short dstHeight; + + unsigned char leftPad; + + } T_image_state; + + T_image_state *imageState_; + + // + // The flags is set according to the + // split load and save policy set by + // the encoding side. + // + + typedef struct + { + int resource; + int current; + int load; + int save; + int commit; + + } T_split_state; + + T_split_state splitState_; + + // + // List of agent resources. + // + + List splitResources_; + + // + // Keep track of object creation and + // deletion. + // + + private: + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +#endif /* ServerChannel_H */ diff --git a/nxcomp/src/ServerProxy.cpp b/nxcomp/src/ServerProxy.cpp new file mode 100644 index 000000000..28f94842a --- /dev/null +++ b/nxcomp/src/ServerProxy.cpp @@ -0,0 +1,621 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "NXalert.h" + +#include "Socket.h" + +#include "ServerProxy.h" + +#include "ServerChannel.h" +#include "GenericChannel.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Log the operations related to sending +// and receiving the control tokens. +// + +#undef TOKEN + +ServerProxy::ServerProxy(int proxyFd) : Proxy(proxyFd) + +{ + xServerAddrFamily_ = -1; + xServerAddrLength_ = 0; + + xServerAddr_ = NULL; + xServerDisplay_ = NULL; + + cupsServerPort_ = NULL; + smbServerPort_ = NULL; + mediaServerPort_ = NULL; + httpServerPort_ = NULL; + + fontServerPort_ = NULL; + + #ifdef DEBUG + *logofs << "ServerProxy: Created new object at " << this + << ".\n" << logofs_flush; + #endif +} + +ServerProxy::~ServerProxy() +{ + delete xServerAddr_; + + delete [] xServerDisplay_; + + delete [] fontServerPort_; + + #ifdef DEBUG + *logofs << "ServerProxy: Deleted object at " << this + << ".\n" << logofs_flush; + #endif +} + +void ServerProxy::handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, + sockaddr *xServerAddr, unsigned int xServerAddrLength) +{ + delete xServerAddr_; + + xServerAddr_ = xServerAddr; + + xServerAddrFamily_ = xServerAddrFamily; + xServerAddrLength_ = xServerAddrLength; + + delete [] xServerDisplay_; + + xServerDisplay_ = new char[strlen(xServerDisplay) + 1]; + + strcpy(xServerDisplay_, xServerDisplay); + + #ifdef DEBUG + *logofs << "ServerProxy: Set display configuration to display '" + << xServerDisplay_ << "'.\n" + << logofs_flush; + #endif +} + +void ServerProxy::handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort) +{ + cupsServerPort_ = cupsServerPort; + smbServerPort_ = smbServerPort; + mediaServerPort_ = mediaServerPort; + httpServerPort_ = httpServerPort; + + delete [] fontServerPort_; + + fontServerPort_ = new char[strlen(fontServerPort) + 1]; + + strcpy(fontServerPort_, fontServerPort); + + #ifdef DEBUG + *logofs << "ServerProxy: Set port configuration to CUPS " + << cupsServerPort_ << ", SMB " << smbServerPort_ + << ", media " << mediaServerPort_ << ", HTTP " + << httpServerPort_ << ".\n" + << logofs_flush; + #endif +} + +int ServerProxy::handleNewConnection(T_channel_type type, int clientFd) +{ + switch (type) + { + case channel_font: + { + return handleNewGenericConnection(clientFd, channel_font, "font"); + } + case channel_slave: + { + return handleNewSlaveConnection(clientFd); + } + default: + { + #ifdef PANIC + *logofs << "ServerProxy: PANIC! Unsupported channel with type '" + << getTypeName(type) << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unsupported channel with type '" + << getTypeName(type) << "'.\n"; + + return -1; + } + } +} + +int ServerProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId) +{ + switch (type) + { + case channel_x11: + { + return handleNewXConnectionFromProxy(channelId); + } + case channel_cups: + { + return handleNewGenericConnectionFromProxy(channelId, channel_cups, + cupsServerPort_, "CUPS"); + } + case channel_smb: + { + smbServerPort_.setDefaultTCPInterface(1); + return handleNewGenericConnectionFromProxy(channelId, channel_smb, + smbServerPort_, "SMB"); + } + case channel_media: + { + return handleNewGenericConnectionFromProxy(channelId, channel_media, + mediaServerPort_, "media"); + } + case channel_http: + { + return handleNewGenericConnectionFromProxy(channelId, channel_http, + httpServerPort_, "HTTP"); + } + case channel_slave: + { + return handleNewSlaveConnectionFromProxy(channelId); + } + default: + { + #ifdef PANIC + *logofs << "ServerProxy: PANIC! Unsupported channel with type '" + << getTypeName(type) << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unsupported channel with type '" + << getTypeName(type) << "'.\n"; + + return -1; + } + } +} + +int ServerProxy::handleNewAgentConnection(Agent *agent) +{ + #ifdef PANIC + *logofs << "ServerProxy: PANIC! Can't create an agent " + << "connection at this side.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't create an agent " + << "connection at this side.\n"; + + return -1; +} + +int ServerProxy::handleNewXConnection(int clientFd) +{ + #ifdef PANIC + *logofs << "ServerProxy: PANIC! Can't create a new X channel " + << "with FD#" << clientFd << " at this side.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't create a new X channel " + << "with FD#" << clientFd << " at this side.\n"; + + return -1; +} + +int ServerProxy::handleNewXConnectionFromProxy(int channelId) +{ + // + // Connect to the real X server. + // + + int retryConnect = control -> OptionServerRetryConnect; + + int xServerFd; + + for (;;) + { + xServerFd = socket(xServerAddrFamily_, SOCK_STREAM, PF_UNSPEC); + + if (xServerFd < 0) + { + #ifdef PANIC + *logofs << "ServerProxy: PANIC! Call to socket failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Call to socket failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + return -1; + } + + #ifdef TEST + *logofs << "ServerProxy: Trying to connect to X server '" + << xServerDisplay_ << "'.\n" << logofs_flush; + #endif + + int result = connect(xServerFd, xServerAddr_, xServerAddrLength_); + + getNewTimestamp(); + + if (result < 0) + { + #ifdef WARNING + *logofs << "ServerProxy: WARNING! Connection to '" + << xServerDisplay_ << "' failed with error '" + << ESTR() << "'. Retrying.\n" << logofs_flush; + #endif + + close(xServerFd); + + if (--retryConnect == 0) + { + #ifdef PANIC + *logofs << "ServerProxy: PANIC! Connection to '" + << xServerDisplay_ << "' for channel ID#" + << channelId << " failed. Error is " + << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Connection to '" + << xServerDisplay_ << "' failed. Error is " + << EGET() << " '" << ESTR() << "'.\n"; + + close(xServerFd); + + return -1; + } + + if (activeChannels_.getSize() == 0) + { + sleep(2); + } + else + { + sleep(1); + } + } + else + { + break; + } + } + + assignChannelMap(channelId, xServerFd); + + #ifdef TEST + *logofs << "ServerProxy: X server descriptor FD#" << xServerFd + << " mapped to channel ID#" << channelId << ".\n" + << logofs_flush; + #endif + + // + // Turn queuing off for path proxy-to-X-server. + // + + if (control -> OptionServerNoDelay == 1) + { + SetNoDelay(xServerFd, control -> OptionServerNoDelay); + } + + // + // If requested, set the size of the TCP send + // and receive buffers. + // + + if (control -> OptionServerSendBuffer != -1) + { + SetSendBuffer(xServerFd, control -> OptionServerSendBuffer); + } + + if (control -> OptionServerReceiveBuffer != -1) + { + SetReceiveBuffer(xServerFd, control -> OptionServerReceiveBuffer); + } + + if (allocateTransport(xServerFd, channelId) < 0) + { + return -1; + } + + // + // Starting from protocol level 3 client and server + // caches are created in proxy and shared between all + // channels. If remote proxy has older protocol level + // pointers are NULL and channels must create their + // own instances. + // + + channels_[channelId] = new ServerChannel(transports_[channelId], compressor_); + + if (channels_[channelId] == NULL) + { + deallocateTransport(channelId); + + return -1; + } + + increaseChannels(channelId); + + // + // Propagate channel stores and caches to the new + // channel. + // + + channels_[channelId] -> setOpcodes(opcodeStore_); + + channels_[channelId] -> setStores(clientStore_, serverStore_); + + channels_[channelId] -> setCaches(clientCache_, serverCache_); + + int port = atoi(fontServerPort_); + + if (port > 0) + { + channels_[channelId] -> setPorts(port); + } + + // + // Let channel configure itself according + // to control parameters. + // + + channels_[channelId] -> handleConfiguration(); + + // + // Check if we have successfully loaded the + // selected cache and, if not, remove it + // from disk. + // + + handleCheckLoad(); + + return 1; +} + +// +// Check if we still need to drop a channel. We need +// to check this explicitly at the time we receive a +// request to load or save the cache because we could +// receive the control message before having entered +// the function handling the channel events. +// + +int ServerProxy::handleCheckDrop() +{ + T_list channelList = activeChannels_.copyList(); + + for (T_list::iterator j = channelList.begin(); + j != channelList.end(); j++) + { + int channelId = *j; + + if (channels_[channelId] != NULL && + (channels_[channelId] -> getDrop() == 1 || + channels_[channelId] -> getClosing() == 1)) + { + #ifdef TEST + *logofs << "ServerProxy: Dropping the descriptor FD#" + << getFd(channelId) << " channel ID#" + << channelId << ".\n" << logofs_flush; + #endif + + handleDrop(channelId); + } + } + + return 1; +} + +int ServerProxy::handleCheckLoad() +{ + // + // Check if we just created the first X channel + // but the client side didn't tell us to load + // the cache selected at the session negotiation. + // This is very likely because the load operation + // failed at the remote side, for example because + // the cache was invalid or corrupted. + // + + int channelCount = getChannels(channel_x11); + + if (channelCount != 1) + { + return 0; + } + + if (control -> PersistentCacheEnableLoad == 1 && + control -> PersistentCachePath != NULL && + control -> PersistentCacheName != NULL && + isTimestamp(timeouts_.loadTs) == 0) + { + #ifdef WARNING + *logofs << "ServerProxy: WARNING! Cache file '" << control -> PersistentCachePath + << "/" << control -> PersistentCacheName << "' not loaded.\n" + << logofs_flush; + #endif + + // + // Remove the cache file. + // + + #ifdef WARNING + *logofs << "ServerProxy: WARNING! Removing supposedly " + << "incompatible cache '" << control -> PersistentCachePath + << "/" << control -> PersistentCacheName + << "'.\n" << logofs_flush; + #endif + + handleResetPersistentCache(); + } + + return 1; +} + +int ServerProxy::handleLoadFromProxy() +{ + // + // Be sure we drop any confirmed channel. + // + + handleCheckDrop(); + + // + // Check that either no X channel is + // remaining or we are inside a reset. + // + + int channelCount = getChannels(channel_x11); + + if (channelCount > 0) + { + #ifdef PANIC + *logofs << "ServerProxy: PANIC! Protocol violation " + << "in command load with " << channelCount + << " channels.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Protocol violation " + << "in command load from proxy.\n"; + + return -1; + } + else if (handleLoadStores() < 0) + { + #ifdef WARNING + *logofs << "ServerProxy: WARNING! Failed to load content " + << "of persistent cache.\n" << logofs_flush; + #endif + + return -1; + } + + return 1; +} + +int ServerProxy::handleSaveFromProxy() +{ + // + // Be sure we drop any confirmed channel. + // + + handleCheckDrop(); + + // + // Now verify that all channels are gone. + // + + int channelCount = getChannels(channel_x11); + + if (channelCount > 0) + { + #ifdef PANIC + *logofs << "ServerProxy: PANIC! Protocol violation " + << "in command save with " << channelCount + << " channels.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Protocol violation " + << "in command save from proxy.\n"; + + return -1; + } + else if (handleSaveStores() < 0) + { + #ifdef PANIC + *logofs << "ServerProxy: PANIC! Failed to save stores " + << "to persistent cache.\n" << logofs_flush; + #endif + + return -1; + } + + return 1; +} + +int ServerProxy::handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient) const +{ + if (clientStore_ -> saveRequestStores(cachefs, md5StateStream, md5StateClient, + discard_checksum, use_data) < 0) + { + return -1; + } + else if (serverStore_ -> saveReplyStores(cachefs, md5StateStream, md5StateClient, + use_checksum, discard_data) < 0) + { + return -1; + } + else if (serverStore_ -> saveEventStores(cachefs, md5StateStream, md5StateClient, + use_checksum, discard_data) < 0) + { + return -1; + } + + return 1; +} + +int ServerProxy::handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const +{ + if (clientStore_ -> loadRequestStores(cachefs, md5StateStream, + discard_checksum, use_data) < 0) + { + return -1; + } + else if (serverStore_ -> loadReplyStores(cachefs, md5StateStream, + use_checksum, discard_data) < 0) + { + return -1; + } + else if (serverStore_ -> loadEventStores(cachefs, md5StateStream, + use_checksum, discard_data) < 0) + { + return -1; + } + + return 1; +} diff --git a/nxcomp/src/ServerProxy.h b/nxcomp/src/ServerProxy.h new file mode 100644 index 000000000..e169c4aec --- /dev/null +++ b/nxcomp/src/ServerProxy.h @@ -0,0 +1,154 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ServerProxy_H +#define ServerProxy_H + +#include +#include + +#include "Proxy.h" + +#include "Misc.h" +#include "ChannelEndPoint.h" + +// +// Set the verbosity level. +// + +#undef TEST +#undef DEBUG + +class ServerProxy : public Proxy +{ + public: + + ServerProxy(int proxyFd); + + virtual ~ServerProxy(); + + virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, + sockaddr *xServerAddr, unsigned int xServerAddrLength); + + virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort); + + protected: + + // + // Create a new channel. + // + + virtual int handleNewConnection(T_channel_type type, int clientFd); + + virtual int handleNewConnectionFromProxy(T_channel_type type, int channelId); + + virtual int handleNewAgentConnection(Agent *agent); + + virtual int handleNewXConnection(int clientFd); + + virtual int handleNewXConnectionFromProxy(int channelId); + + // + // Implement persistence according + // to our proxy mode. + // + + virtual int handleLoad(T_load_type type) + { + return 0; + } + + virtual int handleSave() + { + return 0; + } + + virtual int handleAsyncEvents() + { + return 0; + } + + virtual int handleLoadFromProxy(); + virtual int handleSaveFromProxy(); + + virtual int handleSaveAllStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient) const; + + virtual int handleLoadAllStores(istream *cachefs, md5_state_t *md5StateStream) const; + + int handleCheckDrop(); + int handleCheckLoad(); + + // + // Utility function used to realize + // a new connection. + // + + protected: + + virtual int checkLocalChannelMap(int channelId) + { + // Since ProtoStep7 (#issue 108) + return ((channelId & control -> ChannelMask) == 0); + } + + private: + + // FIXME: Use a ChannelEndPoint object also for the X server! + int xServerAddrFamily_; + sockaddr *xServerAddr_; + unsigned int xServerAddrLength_; + + // + // This is the name of the X display where + // we are going to forward connections. + // + + char *xServerDisplay_; + + // + // Ports where to forward extended services' + // TCP connections. + // + + ChannelEndPoint cupsServerPort_; + ChannelEndPoint smbServerPort_; + ChannelEndPoint mediaServerPort_; + ChannelEndPoint httpServerPort_; + + // + // It will have to be passed to the channel + // so that it can set the port where the + // font server connections are tunneled. + // + + char *fontServerPort_; +}; + +#endif /* ServerProxy_H */ diff --git a/nxcomp/src/ServerReadBuffer.cpp b/nxcomp/src/ServerReadBuffer.cpp new file mode 100644 index 000000000..277b85216 --- /dev/null +++ b/nxcomp/src/ServerReadBuffer.cpp @@ -0,0 +1,247 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ServerReadBuffer.h" +#include "ServerChannel.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +unsigned int ServerReadBuffer::suggestedLength(unsigned int pendingLength) +{ + // + // Always read all the data that + // is available. + // + + int readable = transport_ -> readable(); + + unsigned int readLength = (readable == -1 ? 0 : (unsigned int) readable); + + if (readLength < pendingLength) + { + readLength = pendingLength; + } + + // + // Even if the readable data is not + // enough to make a complete message, + // resize the buffer to accommodate + // it all. + // + + if (pendingLength < remaining_) + { + readLength = remaining_; + } + + return readLength; +} + +int ServerReadBuffer::locateMessage(const unsigned char *start, + const unsigned char *end, + unsigned int &controlLength, + unsigned int &dataLength, + unsigned int &trailerLength) +{ + unsigned int size = end - start; + + #ifdef TEST + *logofs << "ServerReadBuffer: Locating message for FD#" + << transport_ -> fd() << " with " << size + << " bytes.\n" << logofs_flush; + #endif + + if (firstMessage_) + { + if (size < 8) + { + remaining_ = 8 - size; + + #ifdef TEST + *logofs << "ServerReadBuffer: No message was located " + << "with remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + + dataLength = 8 + (GetUINT(start + 6, bigEndian_) << 2); + } + else + { + if (size < 32) + { + remaining_ = 32 - size; + + #ifdef TEST + *logofs << "ServerReadBuffer: No message was located " + << "with remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + + if (*start == 1) + { + dataLength = 32 + (GetULONG(start + 4, bigEndian_) << 2); + } + else + { + dataLength = 32; + } + + if (dataLength < 32) + { + #ifdef TEST + *logofs << "ServerReadBuffer: WARNING! Assuming length 32 " + << "for suspicious message of length " << dataLength + << ".\n" << logofs_flush; + #endif + + dataLength = 32; + } + } + + #ifdef TEST + *logofs << "ServerReadBuffer: Length of the next message is " + << dataLength << ".\n" << logofs_flush; + #endif + + if (size < dataLength) + { + remaining_ = dataLength - size; + + #ifdef TEST + *logofs << "ServerReadBuffer: No message was located " + << "with remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + + firstMessage_ = 0; + + controlLength = 0; + trailerLength = 0; + + remaining_ = 0; + + #ifdef TEST + *logofs << "ServerReadBuffer: Located message with " + << "remaining " << remaining_ << ".\n" + << logofs_flush; + #endif + + return 1; +} + +// +// Check if the data already read contains a +// message matching the opcode and sequence, +// starting at the given offset. +// + +unsigned char *ServerReadBuffer::peekMessage(unsigned int &offset, unsigned char opcode, + unsigned short sequence) +{ + #ifdef TEST + *logofs << "ServerReadBuffer: Peeking message " + << "for FD#" << transport_ -> fd() << " with size " + << length_ << " offset " << offset << " opcode " + << (unsigned int) opcode << " and sequence " + << sequence << ".\n" << logofs_flush; + #endif + + if (firstMessage_) + { + return NULL; + } + + unsigned char *next = buffer_ + start_ + offset; + unsigned char *end = buffer_ + start_ + length_; + + int found = 0; + + while (end - next >= 32) + { + #ifdef DEBUG + *logofs << "ServerReadBuffer: Checking opcode " + << (unsigned int) *next << " sequence " + << GetUINT(next + 2, bigEndian_) + << " at " << next - buffer_ + start_ + << ".\n" << logofs_flush; + #endif + + if (*next == opcode && GetUINT(next + 2, bigEndian_) == sequence) + { + found = 1; + + break; + } + else if (*next == 1) + { + next += (32 + (GetULONG(next + 4, bigEndian_) << 2)); + } + else + { + next += 32; + } + } + + offset = next - buffer_ + start_; + + if (found == 1) + { + #ifdef TEST + *logofs << "ServerReadBuffer: Found message at " + << "offset " << next - buffer_ + start_ + << ".\n" << logofs_flush; + #endif + + return next; + } + + #ifdef TEST + *logofs << "ServerReadBuffer: Quitting loop at " + << "offset " << next - buffer_ + start_ + << ".\n" << logofs_flush; + #endif + + return NULL; +} diff --git a/nxcomp/src/ServerReadBuffer.h b/nxcomp/src/ServerReadBuffer.h new file mode 100644 index 000000000..d6c207ead --- /dev/null +++ b/nxcomp/src/ServerReadBuffer.h @@ -0,0 +1,73 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ServerReadBuffer_H +#define ServerReadBuffer_H + +#include "ReadBuffer.h" +#include "Control.h" + +class ServerChannel; + +class ServerReadBuffer : public ReadBuffer +{ + public: + + ServerReadBuffer(Transport *transport, ServerChannel *channel) + + : ReadBuffer(transport), firstMessage_(1), channel_(channel) + { + } + + virtual ~ServerReadBuffer() + { + } + + void setBigEndian(int flag) + { + bigEndian_ = flag; + } + + unsigned char *peekMessage(unsigned int &offset, unsigned char opcode, + unsigned short sequence); + + protected: + + virtual unsigned int suggestedLength(unsigned int pendingLength); + + virtual int locateMessage(const unsigned char *start, + const unsigned char *end, + unsigned int &controlLength, + unsigned int &dataLength, + unsigned int &trailerLength); + + int bigEndian_; + + int firstMessage_; + + ServerChannel *channel_; +}; + +#endif /* ServerReadBuffer_H */ diff --git a/nxcomp/src/ServerStore.cpp b/nxcomp/src/ServerStore.cpp new file mode 100644 index 000000000..8123b6de0 --- /dev/null +++ b/nxcomp/src/ServerStore.cpp @@ -0,0 +1,183 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ServerStore.h" + +// +// Cached reply classes. +// + +#include "GetImageReply.h" +#include "ListFontsReply.h" +#include "QueryFontReply.h" +#include "GetPropertyReply.h" +#include "GenericReply.h" + +// +// Set the verbosity level. +// + +#define WARNING +#define PANIC +#undef TEST + +ServerStore::ServerStore(StaticCompressor *compressor) +{ + if (logofs == NULL) + { + logofs = &cout; + } + + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + replies_[i] = NULL; + events_[i] = NULL; + } + + replies_[X_ListFonts] = new ListFontsReplyStore(compressor); + replies_[X_QueryFont] = new QueryFontReplyStore(compressor); + replies_[X_GetImage] = new GetImageReplyStore(compressor); + replies_[X_GetProperty] = new GetPropertyReplyStore(compressor); + + replies_[X_NXInternalGenericReply] = new GenericReplyStore(compressor); +} + +ServerStore::~ServerStore() +{ + if (logofs == NULL) + { + logofs = &cout; + } + + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + delete replies_[i]; + delete events_[i]; + } +} + +int ServerStore::saveReplyStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient, T_checksum_action checksumAction, + T_data_action dataAction) const +{ + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + if (replies_[i] != NULL && + replies_[i] -> saveStore(cachefs, md5StateStream, md5StateClient, + checksumAction, dataAction, + storeBigEndian()) < 0) + { + #ifdef PANIC + *logofs << "ServerStore: PANIC! Error saving reply store " + << "for OPCODE#" << (unsigned int) i << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error saving reply store " + << "for opcode '" << (unsigned int) i << "'.\n"; + + return -1; + } + } + + return 1; +} + +int ServerStore::saveEventStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient, T_checksum_action checksumAction, + T_data_action dataAction) const +{ + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + if (events_[i] != NULL && + events_[i] -> saveStore(cachefs, md5StateStream, md5StateClient, + checksumAction, dataAction, + storeBigEndian()) < 0) + { + #ifdef PANIC + *logofs << "ServerStore: PANIC! Error saving event store " + << "for OPCODE#" << (unsigned int) i << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Error saving event store " + << "for opcode '" << (unsigned int) i << "'.\n"; + + return -1; + } + } + + return 1; +} + +int ServerStore::loadReplyStores(istream *cachefs, md5_state_t *md5StateStream, + T_checksum_action checksumAction, T_data_action dataAction) const +{ + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + if (replies_[i] != NULL && + replies_[i] -> loadStore(cachefs, md5StateStream, + checksumAction, dataAction, + storeBigEndian()) < 0) + { + #ifdef PANIC + *logofs << "ServerStore: PANIC! Error loading reply store " + << "for OPCODE#" << (unsigned int) i << ".\n" + << logofs_flush; + #endif + + return -1; + } + } + + return 1; +} + +int ServerStore::loadEventStores(istream *cachefs, md5_state_t *md5StateStream, + T_checksum_action checksumAction, T_data_action dataAction) const +{ + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + if (events_[i] != NULL && + events_[i] -> loadStore(cachefs, md5StateStream, + checksumAction, dataAction, + storeBigEndian()) < 0) + { + #ifdef PANIC + *logofs << "ServerStore: PANIC! Error loading event store " + << "for OPCODE#" << (unsigned int) i << ".\n" + << logofs_flush; + #endif + + return -1; + } + } + + return 1; +} diff --git a/nxcomp/src/ServerStore.h b/nxcomp/src/ServerStore.h new file mode 100644 index 000000000..dbbb968e5 --- /dev/null +++ b/nxcomp/src/ServerStore.h @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ServerStore_H +#define ServerStore_H + +#include "Message.h" + +#include "ChannelStore.h" + +class StaticCompressor; + +class ServerStore : public ChannelStore +{ + public: + + ServerStore(StaticCompressor *compressor); + + virtual ~ServerStore(); + + MessageStore *getReplyStore(unsigned char opcode) const + { + return replies_[opcode]; + } + + MessageStore *getEventStore(unsigned char opcode) const + { + return events_[opcode]; + } + + // + // Actually save the message store + // to disk according to proxy mode. + // + + int saveReplyStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient, T_checksum_action checksumAction, + T_data_action dataAction) const; + + int saveEventStores(ostream *cachefs, md5_state_t *md5StateStream, + md5_state_t *md5StateClient, T_checksum_action checksumAction, + T_data_action dataAction) const; + + + int loadReplyStores(istream *cachefs, md5_state_t *md5StateStream, + T_checksum_action checksumAction, T_data_action dataAction) const; + + int loadEventStores(istream *cachefs, md5_state_t *md5StateStream, + T_checksum_action checksumAction, T_data_action dataAction) const; + + private: + + // + // A server store contains replies and events. + // + + MessageStore *replies_[CHANNEL_STORE_OPCODE_LIMIT]; + MessageStore *events_[CHANNEL_STORE_OPCODE_LIMIT]; +}; + +#endif /* ServerStore_H */ diff --git a/nxcomp/src/SetClipRectangles.cpp b/nxcomp/src/SetClipRectangles.cpp new file mode 100644 index 000000000..b43cea938 --- /dev/null +++ b/nxcomp/src/SetClipRectangles.cpp @@ -0,0 +1,154 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SetClipRectangles.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int SetClipRectanglesStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; + + // + // Here is the fingerprint. + // + + setClipRectangles -> ordering = *(buffer + 1); + + setClipRectangles -> gcontext = GetULONG(buffer + 4, bigEndian); + + setClipRectangles -> x_origin = GetUINT(buffer + 8, bigEndian); + setClipRectangles -> y_origin = GetUINT(buffer + 10, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int SetClipRectanglesStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; + + // + // Fill all the message's fields. + // + + *(buffer + 1) = setClipRectangles -> ordering; + + PutULONG(setClipRectangles -> gcontext, buffer + 4, bigEndian); + + PutUINT(setClipRectangles -> x_origin, buffer + 8, bigEndian); + PutUINT(setClipRectangles -> y_origin, buffer + 10, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void SetClipRectanglesStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; + + *logofs << name() << ": Identity ordering " << (unsigned int) setClipRectangles -> ordering + << ", gcontext " << setClipRectangles -> gcontext << ", x_origin " + << setClipRectangles -> x_origin << ", y_origin " + << setClipRectangles -> y_origin << ", size " + << setClipRectangles -> size_ << ".\n" << logofs_flush; + #endif +} + +void SetClipRectanglesStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 1, 1); + md5_append(md5_state_, buffer + 8, 4); +} + +void SetClipRectanglesStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; + SetClipRectanglesMessage *cachedSetClipRectangles = (SetClipRectanglesMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " << setClipRectangles -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeXidValue(setClipRectangles -> gcontext, clientCache -> gcCache); + + cachedSetClipRectangles -> gcontext = setClipRectangles -> gcontext; +} + +void SetClipRectanglesStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + SetClipRectanglesMessage *setClipRectangles = (SetClipRectanglesMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + decodeBuffer.decodeXidValue(value, clientCache -> gcCache); + + setClipRectangles -> gcontext = value; + + #ifdef DEBUG + *logofs << name() << ": Decoded value " << setClipRectangles -> gcontext + << " as gcontext field.\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/SetClipRectangles.h b/nxcomp/src/SetClipRectangles.h new file mode 100644 index 000000000..a2245360c --- /dev/null +++ b/nxcomp/src/SetClipRectangles.h @@ -0,0 +1,187 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef SetClipRectangles_H +#define SetClipRectangles_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define SETCLIPRECTANGLES_ENABLE_CACHE 1 +#define SETCLIPRECTANGLES_ENABLE_DATA 0 +#define SETCLIPRECTANGLES_ENABLE_SPLIT 0 +#define SETCLIPRECTANGLES_ENABLE_COMPRESS 0 + +#define SETCLIPRECTANGLES_DATA_LIMIT 2048 +#define SETCLIPRECTANGLES_DATA_OFFSET 12 + +#define SETCLIPRECTANGLES_CACHE_SLOTS 3000 +#define SETCLIPRECTANGLES_CACHE_THRESHOLD 3 +#define SETCLIPRECTANGLES_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class SetClipRectanglesMessage : public Message +{ + friend class SetClipRectanglesStore; + + public: + + SetClipRectanglesMessage() + { + } + + ~SetClipRectanglesMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char ordering; + unsigned int gcontext; + unsigned short x_origin; + unsigned short y_origin; +}; + +class SetClipRectanglesStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + SetClipRectanglesStore() : MessageStore() + { + enableCache = SETCLIPRECTANGLES_ENABLE_CACHE; + enableData = SETCLIPRECTANGLES_ENABLE_DATA; + enableSplit = SETCLIPRECTANGLES_ENABLE_SPLIT; + enableCompress = SETCLIPRECTANGLES_ENABLE_COMPRESS; + + dataLimit = SETCLIPRECTANGLES_DATA_LIMIT; + dataOffset = SETCLIPRECTANGLES_DATA_OFFSET; + + cacheSlots = SETCLIPRECTANGLES_CACHE_SLOTS; + cacheThreshold = SETCLIPRECTANGLES_CACHE_THRESHOLD; + cacheLowerThreshold = SETCLIPRECTANGLES_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~SetClipRectanglesStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "SetClipRectangles"; + } + + virtual unsigned char opcode() const + { + return X_SetClipRectangles; + } + + virtual unsigned int storage() const + { + return sizeof(SetClipRectanglesMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new SetClipRectanglesMessage(); + } + + virtual Message *create(const Message &message) const + { + return new SetClipRectanglesMessage((const SetClipRectanglesMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (SetClipRectanglesMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* SetClipRectangles_H */ diff --git a/nxcomp/src/SetUnpackAlpha.cpp b/nxcomp/src/SetUnpackAlpha.cpp new file mode 100644 index 000000000..5a352d26a --- /dev/null +++ b/nxcomp/src/SetUnpackAlpha.cpp @@ -0,0 +1,266 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SetUnpackAlpha.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +SetUnpackAlphaStore::SetUnpackAlphaStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = SETUNPACKALPHA_ENABLE_CACHE; + enableData = SETUNPACKALPHA_ENABLE_DATA; + enableCompress = SETUNPACKALPHA_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = SETUNPACKALPHA_DATA_LIMIT; + dataOffset = SETUNPACKALPHA_DATA_OFFSET_IF_PROTO_STEP_7; + + cacheSlots = SETUNPACKALPHA_CACHE_SLOTS; + cacheThreshold = SETUNPACKALPHA_CACHE_THRESHOLD; + cacheLowerThreshold = SETUNPACKALPHA_CACHE_LOWER_THRESHOLD; + + // Since ProtoStep8 (#issue 108) + enableSplit = SETUNPACKALPHA_ENABLE_SPLIT_IF_PROTO_STEP_8; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +SetUnpackAlphaStore::~SetUnpackAlphaStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int SetUnpackAlphaStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; + #endif + + // + // Encode the source length first because + // we need it to determine the size of + // the output buffer. + // + + // SrcLength. + encodeBuffer.encodeValue(GetULONG(buffer + 8, bigEndian), 32, 9); + + // Client. + encodeBuffer.encodeCachedValue(*(buffer + 1), 8, + clientCache -> resourceCache); + // Method. + encodeBuffer.encodeCachedValue(*(buffer + 4), 8, + clientCache -> methodCache); + // DstLength. + encodeBuffer.encodeValue(GetULONG(buffer + 12, bigEndian), 32, 9); + + #ifdef DEBUG + *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int SetUnpackAlphaStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; + #endif + + unsigned int value; + unsigned char cValue; + + // SrcLength. + decodeBuffer.decodeValue(value, 32, 9); + + size = RoundUp4(value) + 16; + + buffer = writeBuffer -> addMessage(size); + + PutULONG(value, buffer + 8, bigEndian); + + // Client. + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> resourceCache); + + *(buffer + 1) = cValue; + + // Method. + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> methodCache); + + *(buffer + 4) = cValue; + + // DstLength. + decodeBuffer.decodeValue(value, 32, 9); + + PutULONG(value, buffer + 12, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int SetUnpackAlphaStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; + + setUnpackAlpha -> client = *(buffer + 1); + setUnpackAlpha -> method = *(buffer + 4); + + setUnpackAlpha -> src_length = GetULONG(buffer + 8, bigEndian); + setUnpackAlpha -> dst_length = GetULONG(buffer + 12, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int SetUnpackAlphaStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; + + *(buffer + 1) = setUnpackAlpha -> client; + *(buffer + 4) = setUnpackAlpha -> method; + + PutULONG(setUnpackAlpha -> src_length, buffer + 8, bigEndian); + PutULONG(setUnpackAlpha -> dst_length, buffer + 12, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void SetUnpackAlphaStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; + + *logofs << name() << ": Identity client " + << (unsigned int) setUnpackAlpha -> client << " method " + << (unsigned int) setUnpackAlpha -> method << " source length " + << setUnpackAlpha -> src_length << " destination length " + << setUnpackAlpha -> dst_length << " size " + << setUnpackAlpha -> size_ << ".\n"; + + #endif +} + +void SetUnpackAlphaStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Include the pack method and the source + // and destination length. + // + + md5_append(md5_state_, buffer + 4, 1); + md5_append(md5_state_, buffer + 8, 8); +} + +void SetUnpackAlphaStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; + SetUnpackAlphaMessage *cachedSetUnpackAlpha = (SetUnpackAlphaMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(setUnpackAlpha -> client, 8, + clientCache -> resourceCache); + + cachedSetUnpackAlpha -> client = setUnpackAlpha -> client; +} + +void SetUnpackAlphaStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + SetUnpackAlphaMessage *setUnpackAlpha = (SetUnpackAlphaMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(setUnpackAlpha -> client, 8, + clientCache -> resourceCache); +} diff --git a/nxcomp/src/SetUnpackAlpha.h b/nxcomp/src/SetUnpackAlpha.h new file mode 100644 index 000000000..54714efaa --- /dev/null +++ b/nxcomp/src/SetUnpackAlpha.h @@ -0,0 +1,162 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef SetUnpackAlpha_H +#define SetUnpackAlpha_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define SETUNPACKALPHA_ENABLE_CACHE 1 +#define SETUNPACKALPHA_ENABLE_DATA 1 + +#define SETUNPACKALPHA_DATA_LIMIT 16384 + +#define SETUNPACKALPHA_CACHE_SLOTS 2000 +#define SETUNPACKALPHA_CACHE_THRESHOLD 10 +#define SETUNPACKALPHA_CACHE_LOWER_THRESHOLD 5 + +#define SETUNPACKALPHA_DATA_OFFSET_IF_PROTO_STEP_7 16 +#define SETUNPACKALPHA_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +#define SETUNPACKALPHA_ENABLE_SPLIT_IF_PROTO_STEP_8 0 + +// +// The message class. +// + +class SetUnpackAlphaMessage : public Message +{ + friend class SetUnpackAlphaStore; + + public: + + SetUnpackAlphaMessage() + { + } + + ~SetUnpackAlphaMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char client; + unsigned char method; + + unsigned int src_length; + unsigned int dst_length; +}; + +class SetUnpackAlphaStore : public MessageStore +{ + public: + + SetUnpackAlphaStore(StaticCompressor *compressor); + + virtual ~SetUnpackAlphaStore(); + + virtual const char *name() const + { + return "SetUnpackAlpha"; + } + + virtual unsigned char opcode() const + { + return X_NXSetUnpackAlpha; + } + + virtual unsigned int storage() const + { + return sizeof(SetUnpackAlphaMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new SetUnpackAlphaMessage(); + } + + virtual Message *create(const Message &message) const + { + return new SetUnpackAlphaMessage((const SetUnpackAlphaMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (SetUnpackAlphaMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* SetUnpackAlpha_H */ diff --git a/nxcomp/src/SetUnpackColormap.cpp b/nxcomp/src/SetUnpackColormap.cpp new file mode 100644 index 000000000..2c9bba1bd --- /dev/null +++ b/nxcomp/src/SetUnpackColormap.cpp @@ -0,0 +1,266 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SetUnpackColormap.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +SetUnpackColormapStore::SetUnpackColormapStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = SETUNPACKCOLORMAP_ENABLE_CACHE; + enableData = SETUNPACKCOLORMAP_ENABLE_DATA; + enableCompress = SETUNPACKCOLORMAP_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = SETUNPACKCOLORMAP_DATA_LIMIT; + dataOffset = SETUNPACKCOLORMAP_DATA_OFFSET_IF_PROTO_STEP_7; + + cacheSlots = SETUNPACKCOLORMAP_CACHE_SLOTS; + cacheThreshold = SETUNPACKCOLORMAP_CACHE_THRESHOLD; + cacheLowerThreshold = SETUNPACKCOLORMAP_CACHE_LOWER_THRESHOLD; + + // Since ProtoStep8 (#issue 108) + enableSplit = SETUNPACKCOLORMAP_ENABLE_SPLIT_IF_PROTO_STEP_8; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +SetUnpackColormapStore::~SetUnpackColormapStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int SetUnpackColormapStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; + #endif + + // + // Encode the source length first because + // we need it to determine the size of + // the output buffer. + // + + // SrcLength. + encodeBuffer.encodeValue(GetULONG(buffer + 8, bigEndian), 32, 9); + + // Client. + encodeBuffer.encodeCachedValue(*(buffer + 1), 8, + clientCache -> resourceCache); + // Method. + encodeBuffer.encodeCachedValue(*(buffer + 4), 8, + clientCache -> methodCache); + // DstLength. + encodeBuffer.encodeValue(GetULONG(buffer + 12, bigEndian), 32, 9); + + #ifdef DEBUG + *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int SetUnpackColormapStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; + #endif + + unsigned int value; + unsigned char cValue; + + // SrcLength. + decodeBuffer.decodeValue(value, 32, 9); + + size = RoundUp4(value) + 16; + + buffer = writeBuffer -> addMessage(size); + + PutULONG(value, buffer + 8, bigEndian); + + // Client. + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> resourceCache); + + *(buffer + 1) = cValue; + + // Method. + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> methodCache); + + *(buffer + 4) = cValue; + + // DstLength. + decodeBuffer.decodeValue(value, 32, 9); + + PutULONG(value, buffer + 12, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int SetUnpackColormapStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; + + setUnpackColormap -> client = *(buffer + 1); + setUnpackColormap -> method = *(buffer + 4); + + setUnpackColormap -> src_length = GetULONG(buffer + 8, bigEndian); + setUnpackColormap -> dst_length = GetULONG(buffer + 12, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int SetUnpackColormapStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; + + *(buffer + 1) = setUnpackColormap -> client; + *(buffer + 4) = setUnpackColormap -> method; + + PutULONG(setUnpackColormap -> src_length, buffer + 8, bigEndian); + PutULONG(setUnpackColormap -> dst_length, buffer + 12, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void SetUnpackColormapStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; + + *logofs << name() << ": Identity client " + << (unsigned int) setUnpackColormap -> client << " method " + << (unsigned int) setUnpackColormap -> method << " source length " + << setUnpackColormap -> src_length << " destination length " + << setUnpackColormap -> dst_length << " size " + << setUnpackColormap -> size_ << ".\n"; + + #endif +} + +void SetUnpackColormapStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Include the pack method and the source + // and destination length. + // + + md5_append(md5_state_, buffer + 4, 1); + md5_append(md5_state_, buffer + 8, 8); +} + +void SetUnpackColormapStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; + SetUnpackColormapMessage *cachedSetUnpackColormap = (SetUnpackColormapMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + encodeBuffer.encodeCachedValue(setUnpackColormap -> client, 8, + clientCache -> resourceCache); + + cachedSetUnpackColormap -> client = setUnpackColormap -> client; +} + +void SetUnpackColormapStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + SetUnpackColormapMessage *setUnpackColormap = (SetUnpackColormapMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(setUnpackColormap -> client, 8, + clientCache -> resourceCache); +} diff --git a/nxcomp/src/SetUnpackColormap.h b/nxcomp/src/SetUnpackColormap.h new file mode 100644 index 000000000..779366531 --- /dev/null +++ b/nxcomp/src/SetUnpackColormap.h @@ -0,0 +1,162 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef SetUnpackColormap_H +#define SetUnpackColormap_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define SETUNPACKCOLORMAP_ENABLE_CACHE 1 +#define SETUNPACKCOLORMAP_ENABLE_DATA 1 + +#define SETUNPACKCOLORMAP_DATA_LIMIT 4096 + +#define SETUNPACKCOLORMAP_CACHE_SLOTS 2000 +#define SETUNPACKCOLORMAP_CACHE_THRESHOLD 5 +#define SETUNPACKCOLORMAP_CACHE_LOWER_THRESHOLD 0 + +#define SETUNPACKCOLORMAP_DATA_OFFSET_IF_PROTO_STEP_7 16 +#define SETUNPACKCOLORMAP_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +#define SETUNPACKCOLORMAP_ENABLE_SPLIT_IF_PROTO_STEP_8 0 + +// +// The message class. +// + +class SetUnpackColormapMessage : public Message +{ + friend class SetUnpackColormapStore; + + public: + + SetUnpackColormapMessage() + { + } + + ~SetUnpackColormapMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char client; + unsigned char method; + + unsigned int src_length; + unsigned int dst_length; +}; + +class SetUnpackColormapStore : public MessageStore +{ + public: + + SetUnpackColormapStore(StaticCompressor *compressor); + + virtual ~SetUnpackColormapStore(); + + virtual const char *name() const + { + return "SetUnpackColormap"; + } + + virtual unsigned char opcode() const + { + return X_NXSetUnpackColormap; + } + + virtual unsigned int storage() const + { + return sizeof(SetUnpackColormapMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new SetUnpackColormapMessage(); + } + + virtual Message *create(const Message &message) const + { + return new SetUnpackColormapMessage((const SetUnpackColormapMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (SetUnpackColormapMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* SetUnpackColormap_H */ diff --git a/nxcomp/src/SetUnpackGeometry.cpp b/nxcomp/src/SetUnpackGeometry.cpp new file mode 100644 index 000000000..edff6a544 --- /dev/null +++ b/nxcomp/src/SetUnpackGeometry.cpp @@ -0,0 +1,305 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SetUnpackGeometry.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +SetUnpackGeometryStore::SetUnpackGeometryStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = SETUNPACKGEOMETRY_ENABLE_CACHE; + enableData = SETUNPACKGEOMETRY_ENABLE_DATA; + enableSplit = SETUNPACKGEOMETRY_ENABLE_SPLIT; + enableCompress = SETUNPACKGEOMETRY_ENABLE_COMPRESS; + + dataLimit = SETUNPACKGEOMETRY_DATA_LIMIT; + dataOffset = SETUNPACKGEOMETRY_DATA_OFFSET; + + cacheSlots = SETUNPACKGEOMETRY_CACHE_SLOTS; + cacheThreshold = SETUNPACKGEOMETRY_CACHE_THRESHOLD; + cacheLowerThreshold = SETUNPACKGEOMETRY_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +SetUnpackGeometryStore::~SetUnpackGeometryStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int SetUnpackGeometryStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(*(buffer + 1), 8, + clientCache -> resourceCache); + + const unsigned char *nextChar = buffer + 4; + + for (int i = 0; i < 6; i++) + { + encodeBuffer.encodeCachedValue(*nextChar++, 8, + clientCache -> depthCache); + } + + encodeBuffer.encodeValue(GetULONG(buffer + 12, bigEndian), 32); + encodeBuffer.encodeValue(GetULONG(buffer + 16, bigEndian), 32); + encodeBuffer.encodeValue(GetULONG(buffer + 20, bigEndian), 32); + + #ifdef DEBUG + *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int SetUnpackGeometryStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; + #endif + + size = 24; + buffer = writeBuffer -> addMessage(size); + + unsigned char cValue; + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> resourceCache); + *(buffer + 1) = cValue; + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + *(buffer + 4) = cValue; + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + *(buffer + 5) = cValue; + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + *(buffer + 6) = cValue; + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + *(buffer + 7) = cValue; + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + *(buffer + 8) = cValue; + + decodeBuffer.decodeCachedValue(cValue, 8, + clientCache -> depthCache); + *(buffer + 9) = cValue; + + unsigned int value; + + decodeBuffer.decodeValue(value, 32); + PutULONG(value, buffer + 12, bigEndian); + + decodeBuffer.decodeValue(value, 32); + PutULONG(value, buffer + 16, bigEndian); + + decodeBuffer.decodeValue(value, 32); + PutULONG(value, buffer + 20, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int SetUnpackGeometryStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; + + setUnpackGeometry -> client = *(buffer + 1); + + setUnpackGeometry -> depth_1_bpp = *(buffer + 4); + setUnpackGeometry -> depth_4_bpp = *(buffer + 5); + setUnpackGeometry -> depth_8_bpp = *(buffer + 6); + setUnpackGeometry -> depth_16_bpp = *(buffer + 7); + setUnpackGeometry -> depth_24_bpp = *(buffer + 8); + setUnpackGeometry -> depth_32_bpp = *(buffer + 9); + + setUnpackGeometry -> red_mask = GetULONG(buffer + 12, bigEndian); + setUnpackGeometry -> green_mask = GetULONG(buffer + 16, bigEndian); + setUnpackGeometry -> blue_mask = GetULONG(buffer + 20, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +int SetUnpackGeometryStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; + + *(buffer + 1) = setUnpackGeometry -> client; + + *(buffer + 4) = setUnpackGeometry -> depth_1_bpp; + *(buffer + 5) = setUnpackGeometry -> depth_4_bpp; + *(buffer + 6) = setUnpackGeometry -> depth_8_bpp; + *(buffer + 7) = setUnpackGeometry -> depth_16_bpp; + *(buffer + 8) = setUnpackGeometry -> depth_24_bpp; + *(buffer + 9) = setUnpackGeometry -> depth_32_bpp; + + PutULONG(setUnpackGeometry -> red_mask, buffer + 12, bigEndian); + PutULONG(setUnpackGeometry -> green_mask, buffer + 16, bigEndian); + PutULONG(setUnpackGeometry -> blue_mask, buffer + 20, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << message << ".\n" << logofs_flush; + #endif + + return 1; +} + +void SetUnpackGeometryStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; + + *logofs << name() << ": Identity client " + << (unsigned) setUnpackGeometry -> client << " depth_1_bpp " + << (unsigned) setUnpackGeometry -> depth_1_bpp << " depth_4_bpp " + << (unsigned int) setUnpackGeometry -> depth_4_bpp << " depth_8_bpp " + << (unsigned int) setUnpackGeometry -> depth_8_bpp << " depth_16_bpp " + << (unsigned int) setUnpackGeometry -> depth_16_bpp << " depth_24_bpp " + << (unsigned int) setUnpackGeometry -> depth_24_bpp << " depth_32_bpp " + << (unsigned int) setUnpackGeometry -> depth_32_bpp + + << " red_mask " << setUnpackGeometry -> red_mask + << " green_mask " << setUnpackGeometry -> green_mask + << " blue_mask " << setUnpackGeometry -> blue_mask + + << " size " << setUnpackGeometry -> size_ << ".\n"; + + #endif +} + +void SetUnpackGeometryStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 4, 6); + md5_append(md5_state_, buffer + 12, 12); +} + +void SetUnpackGeometryStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; + SetUnpackGeometryMessage *cachedSetUnpackGeometry = (SetUnpackGeometryMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef TEST + *logofs << name() << ": Encoding value " + << (unsigned int) setUnpackGeometry -> client + << " as client field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue(setUnpackGeometry -> client, 8, + clientCache -> resourceCache); + + cachedSetUnpackGeometry -> client = setUnpackGeometry -> client; +} + +void SetUnpackGeometryStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + SetUnpackGeometryMessage *setUnpackGeometry = (SetUnpackGeometryMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + decodeBuffer.decodeCachedValue(setUnpackGeometry -> client, 8, + clientCache -> resourceCache); + + #ifdef DEBUG + *logofs << name() << ": Decoded value " + << (unsigned int) setUnpackGeometry -> client + << " as client field.\n" << logofs_flush; + #endif +} diff --git a/nxcomp/src/SetUnpackGeometry.h b/nxcomp/src/SetUnpackGeometry.h new file mode 100644 index 000000000..96104f57f --- /dev/null +++ b/nxcomp/src/SetUnpackGeometry.h @@ -0,0 +1,167 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef SetUnpackGeometry_H +#define SetUnpackGeometry_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define SETUNPACKGEOMETRY_ENABLE_CACHE 1 +#define SETUNPACKGEOMETRY_ENABLE_DATA 0 +#define SETUNPACKGEOMETRY_ENABLE_SPLIT 0 +#define SETUNPACKGEOMETRY_ENABLE_COMPRESS 0 + +#define SETUNPACKGEOMETRY_DATA_LIMIT 24 +#define SETUNPACKGEOMETRY_DATA_OFFSET 24 + +#define SETUNPACKGEOMETRY_CACHE_SLOTS 20 +#define SETUNPACKGEOMETRY_CACHE_THRESHOLD 1 +#define SETUNPACKGEOMETRY_CACHE_LOWER_THRESHOLD 0 + +// +// The message class. +// + +class SetUnpackGeometryMessage : public Message +{ + friend class SetUnpackGeometryStore; + + public: + + SetUnpackGeometryMessage() + { + } + + ~SetUnpackGeometryMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned char client; + + unsigned char depth_1_bpp; + unsigned char depth_4_bpp; + unsigned char depth_8_bpp; + unsigned char depth_16_bpp; + unsigned char depth_24_bpp; + unsigned char depth_32_bpp; + + unsigned int red_mask; + unsigned int green_mask; + unsigned int blue_mask; +}; + +class SetUnpackGeometryStore : public MessageStore +{ + public: + + SetUnpackGeometryStore(StaticCompressor *compressor); + + virtual ~SetUnpackGeometryStore(); + + virtual const char *name() const + { + return "SetUnpackGeometry"; + } + + virtual unsigned char opcode() const + { + return X_NXSetUnpackGeometry; + } + + virtual unsigned int storage() const + { + return sizeof(SetUnpackGeometryMessage); + } + + // + // Message handling methods. + // + + protected: + + virtual Message *create() const + { + return new SetUnpackGeometryMessage(); + } + + virtual Message *create(const Message &message) const + { + return new SetUnpackGeometryMessage((const SetUnpackGeometryMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (SetUnpackGeometryMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* SetUnpackGeometry_H */ diff --git a/nxcomp/src/ShapeExtension.cpp b/nxcomp/src/ShapeExtension.cpp new file mode 100644 index 000000000..2ee2b67db --- /dev/null +++ b/nxcomp/src/ShapeExtension.cpp @@ -0,0 +1,305 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ShapeExtension.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "WriteBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Constructors and destructors. +// + +ShapeExtensionStore::ShapeExtensionStore(StaticCompressor *compressor) + + : MessageStore(compressor) +{ + enableCache = SHAPEEXTENSION_ENABLE_CACHE; + enableData = SHAPEEXTENSION_ENABLE_DATA; + enableSplit = SHAPEEXTENSION_ENABLE_SPLIT; + + // Since ProtoStep7 (#issue 108) + enableCompress = SHAPEEXTENSION_ENABLE_COMPRESS_IF_PROTO_STEP_7; + + dataLimit = SHAPEEXTENSION_DATA_LIMIT; + dataOffset = SHAPEEXTENSION_DATA_OFFSET; + + cacheSlots = SHAPEEXTENSION_CACHE_SLOTS; + cacheThreshold = SHAPEEXTENSION_CACHE_THRESHOLD; + cacheLowerThreshold = SHAPEEXTENSION_CACHE_LOWER_THRESHOLD; + + opcode_ = X_NXInternalShapeExtension; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; +} + +ShapeExtensionStore::~ShapeExtensionStore() +{ + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); +} + +// +// Here are the methods to handle messages' content. +// + +int ShapeExtensionStore::encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const +{ + // + // Handle this extension in a way similar to shape. + // + + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Encoding full message identity.\n" << logofs_flush; + #endif + + // + // We handle all possible requests of this extension + // using the same opcode. We give to message a data + // offset of 4 (or 16 if proto is >= 3) and handle + // the first 16 bytes through an array of caches. + // + + encodeBuffer.encodeValue(size >> 2, 16, 10); + + encodeBuffer.encodeCachedValue(*(buffer + 1), 8, + clientCache -> shapeOpcodeCache); + + for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) + { + encodeBuffer.encodeCachedValue(GetUINT(buffer + (i * 2) + 4, bigEndian), 16, + *clientCache -> shapeDataCache[i]); + } + + #ifdef DEBUG + *logofs << name() << ": Encoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int ShapeExtensionStore::decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const +{ + ClientCache *clientCache = (ClientCache *) channelCache; + + #ifdef DEBUG + *logofs << name() << ": Decoding full message identity.\n" << logofs_flush; + #endif + + decodeBuffer.decodeValue(size, 16, 10); + + size <<= 2; + + buffer = writeBuffer -> addMessage(size); + + decodeBuffer.decodeCachedValue(*(buffer + 1), 8, + clientCache -> shapeOpcodeCache); + + unsigned int value; + + for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache -> shapeDataCache[i]); + + PutUINT(value, buffer + 4 + (i * 2), bigEndian); + } + + #ifdef DEBUG + *logofs << name() << ": Decoded full message identity.\n" << logofs_flush; + #endif + + return 1; +} + +int ShapeExtensionStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; + + shapeExtension -> opcode = *(buffer + 1); + + for (unsigned int i = 0; i < 8; i++) + { + if ((i * 2 + 4) < size) + { + shapeExtension -> data[i] = GetUINT(buffer + i * 2 + 4, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed data[" << i << "].\n" + << logofs_flush; + #endif + } + else + { + shapeExtension -> data[i] = 0; + } + } + + #ifdef DEBUG + *logofs << name() << ": Parsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int ShapeExtensionStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; + + *(buffer + 1) = shapeExtension -> opcode; + + for (unsigned int i = 0; i < 8 && (i * 2 + 4) < size; i++) + { + PutUINT(shapeExtension -> data[i], buffer + i * 2 + 4, bigEndian); + } + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " + << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void ShapeExtensionStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; + + *logofs << name() << ": Identity opcode " << (unsigned) shapeExtension -> opcode; + + for (int i = 0; i < 8; i++) + { + *logofs << ", data[" << i << "] " << shapeExtension -> data[i]; + } + + *logofs << ", size " << shapeExtension -> size_ << ".\n" << logofs_flush; + + #endif +} + +void ShapeExtensionStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + // + // Include minor opcode in the checksum. As data + // offset can be beyond the real end of message, + // we need to include size or we will match any + // message of size less or equal to data offset. + // + + md5_append(md5_state_, buffer + 1, 3); +} + +void ShapeExtensionStore::updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const +{ + // + // Encode the variant part. + // + + ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; + ShapeExtensionMessage *cachedShapeExtension = (ShapeExtensionMessage *) cachedMessage; + + ClientCache *clientCache = (ClientCache *) channelCache; + + for (int i = 0; i < 8 && (i * 2 + 4) < shapeExtension -> size_; i++) + { + #ifdef TEST + *logofs << name() << ": Encoding value " << shapeExtension -> data[i] + << " as data[" << i << "] field.\n" << logofs_flush; + #endif + + encodeBuffer.encodeCachedValue((unsigned int) shapeExtension -> data[i], 16, + *clientCache -> shapeDataCache[i]); + + cachedShapeExtension -> data[i] = shapeExtension -> data[i]; + } +} + +void ShapeExtensionStore::updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const +{ + ShapeExtensionMessage *shapeExtension = (ShapeExtensionMessage *) message; + + ClientCache *clientCache = (ClientCache *) channelCache; + + unsigned int value; + + for (int i = 0; i < 8 && (i * 2 + 4) < shapeExtension -> size_; i++) + { + decodeBuffer.decodeCachedValue(value, 16, + *clientCache -> shapeDataCache[i]); + + shapeExtension -> data[i] = (unsigned short) value; + + #ifdef TEST + *logofs << name() << ": Decoded value " << shapeExtension -> data[i] + << " as data[" << i << "] field.\n" << logofs_flush; + #endif + } +} diff --git a/nxcomp/src/ShapeExtension.h b/nxcomp/src/ShapeExtension.h new file mode 100644 index 000000000..4dd636847 --- /dev/null +++ b/nxcomp/src/ShapeExtension.h @@ -0,0 +1,164 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef ShapeExtension_H +#define ShapeExtension_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define SHAPEEXTENSION_ENABLE_CACHE 1 +#define SHAPEEXTENSION_ENABLE_DATA 1 +#define SHAPEEXTENSION_ENABLE_SPLIT 0 + +#define SHAPEEXTENSION_DATA_LIMIT 3200 +#define SHAPEEXTENSION_DATA_OFFSET 20 + +#define SHAPEEXTENSION_CACHE_SLOTS 3000 +#define SHAPEEXTENSION_CACHE_THRESHOLD 10 +#define SHAPEEXTENSION_CACHE_LOWER_THRESHOLD 5 + +#define SHAPEEXTENSION_ENABLE_COMPRESS_IF_PROTO_STEP_7 0 + +// +// The message class. +// + +class ShapeExtensionMessage : public Message +{ + friend class ShapeExtensionStore; + + public: + + ShapeExtensionMessage() + { + } + + ~ShapeExtensionMessage() + { + } + + // + // Note for encoding in protocol level 1: we consider + // for this message a data offset of 4. Bytes from 5 + // to 20, if present, are taken as part of identity + // and encoded through an array of int caches. + // + + private: + + unsigned char opcode; + unsigned short data[8]; +}; + +class ShapeExtensionStore : public MessageStore +{ + public: + + ShapeExtensionStore(StaticCompressor *compressor); + + virtual ~ShapeExtensionStore(); + + virtual const char *name() const + { + return "ShapeExtension"; + } + + virtual unsigned char opcode() const + { + return opcode_; + } + + virtual unsigned int storage() const + { + return sizeof(ShapeExtensionMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new ShapeExtensionMessage(); + } + + virtual Message *create(const Message &message) const + { + return new ShapeExtensionMessage((const ShapeExtensionMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (ShapeExtensionMessage *) message; + } + + virtual int encodeIdentity(EncodeBuffer &encodeBuffer, const unsigned char *buffer, + const unsigned int size, int bigEndian, + ChannelCache *channelCache) const; + + virtual int decodeIdentity(DecodeBuffer &decodeBuffer, unsigned char *&buffer, + unsigned int &size, int bigEndian, WriteBuffer *writeBuffer, + ChannelCache *channelCache) const; + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void updateIdentity(EncodeBuffer &encodeBuffer, const Message *message, + const Message *cachedMessage, + ChannelCache *channelCache) const; + + virtual void updateIdentity(DecodeBuffer &decodeBuffer, const Message *message, + ChannelCache *channelCache) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; + + private: + + unsigned char opcode_; +}; + +#endif /* ShapeExtension_H */ diff --git a/nxcomp/src/Socket.cpp b/nxcomp/src/Socket.cpp new file mode 100644 index 000000000..8be04d76d --- /dev/null +++ b/nxcomp/src/Socket.cpp @@ -0,0 +1,757 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#if defined(__CYGWIN32__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun) +#include +#endif + +#ifdef __sun +#include +#include +#endif + +#include +#include +#include +#include + +#include +#include + +// +// System specific defines. +// + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun) +#define SOL_IP IPPROTO_IP +#endif + +#ifdef __sun +#define INADDR_NONE ((unsigned int) -1) +#endif + +// +// The TIOCOUTQ ioctl is not implemented on Cygwin. +// Note also that TIOCOUTQ and IPTOS_LOWDELAY are +// disabled when running on MacOS/X. +// + +#ifdef __CYGWIN32__ +#define TIOCOUTQ ((unsigned int) -1) +#endif + +// +// NX includes. +// + +#include "Misc.h" +#include "Socket.h" + +// +// Set verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Set this only once by querying OS details. +// + +static int _kernelStep = -1; + +int GetKernelStep() +{ + if (_kernelStep < 0) + { + // + // At the moment only NX clients run on Win32 + // and MacOS/X so we are not really interested + // in the relevant OS dependent functions. + // + + #if defined(__CYGWIN32__) || defined(__APPLE__) + + _kernelStep = 0; + + #else + + struct utsname buffer; + + if (uname(&buffer) < 0) + { + #ifdef WARNING + *logofs << "Socket: WARNING! Failed to get system info. Error is " + << EGET() << " '" << ESTR() << "'.\n" << logofs_flush; + + *logofs << "Socket: WARNING! Assuming lowest system support.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Failed to get system info. Error is " + << EGET() << " '" << ESTR() << "'.\n"; + + cerr << "Warning" << ": Assuming lowest system support.\n"; + + _kernelStep = 0; + } + else + { + #ifdef TEST + *logofs << "Socket: System is '" << buffer.sysname + << "' nodename '" << buffer.nodename << "' release '" + << buffer.release << "'.\n" << logofs_flush; + + *logofs << "Socket: Version is '" << buffer.version << "' machine '" + << buffer.machine << "'.\n" << logofs_flush; + #endif + + // + // Should test support on other operating systems. + // + + if (strcmp(buffer.sysname, "Linux") == 0) + { + if (strncmp(buffer.release, "2.0.", 4) == 0 || + strncmp(buffer.release, "2.2.", 4) == 0) + { + #ifdef TEST + *logofs << "Socket: Assuming level 2 system support.\n" + << logofs_flush; + #endif + + _kernelStep = 2; + } + else + { + #ifdef TEST + *logofs << "Socket: Assuming level 3 system support.\n" + << logofs_flush; + #endif + + _kernelStep = 3; + } + } + else if (strcmp(buffer.sysname, "SunOS") == 0) + { + #ifdef TEST + *logofs << "Socket: Assuming level 1 system support.\n" + << logofs_flush; + #endif + + _kernelStep = 1; + } + else + { + #ifdef TEST + *logofs << "Socket: Assuming level 0 system support.\n" + << logofs_flush; + #endif + + _kernelStep = 0; + } + } + + #endif /* #if defined(__CYGWIN32__) || defined(__APPLE__) */ + } + + return _kernelStep; +} + +int SetReuseAddress(int fd) +{ + int flag = 1; + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (char *) &flag, sizeof(flag)) < 0) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to set SO_REUSEADDR flag on FD#" + << fd << ". Error is " << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed to set SO_REUSEADDR flag on FD#" + << fd << ". Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + return -1; + } + #ifdef TEST + else + { + *logofs << "Socket: Set SO_REUSEADDR flag on FD#" + << fd << ".\n" << logofs_flush; + } + #endif + + return 1; +} + +int SetNonBlocking(int fd, int value) +{ + int flags = fcntl(fd, F_GETFL); + + if (flags >= 0) + { + if (value == 0) + { + flags &= ~O_NONBLOCK; + } + else + { + flags |= O_NONBLOCK; + } + } + + if (flags < 0 || fcntl(fd, F_SETFL, flags) < 0) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to set O_NONBLOCK flag on FD#" + << fd << " to " << value << ". Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to set O_NONBLOCK flag on FD#" + << fd << " to " << value << ". Error is " << EGET() + << " '" << ESTR() << "'.\n"; + + return -1; + } + #ifdef TEST + else + { + *logofs << "Socket: Set O_NONBLOCK flag on FD#" + << fd << " to " << value << ".\n" + << logofs_flush; + } + #endif + + return 1; +} + +int SetLingerTimeout(int fd, int timeout) +{ + struct linger linger_value; + + if (timeout > 0) + { + linger_value.l_onoff = 1; + linger_value.l_linger = timeout; + } + else + { + linger_value.l_onoff = 0; + linger_value.l_linger = 0; + } + + if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger_value, sizeof(linger_value)) < 0) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to set SO_LINGER values to " + << linger_value.l_onoff << " and " << linger_value.l_linger + << " on FD#" << fd << ". Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to set SO_LINGER values to " + << linger_value.l_onoff << " and " << linger_value.l_linger + << " on FD#" << fd << ". Error is " << EGET() << " '" + << ESTR() << "'.\n"; + + return -1; + } + #ifdef TEST + else + { + *logofs << "Socket: Set SO_LINGER values to " + << linger_value.l_onoff << " and " << linger_value.l_linger + << " on FD#" << fd << ".\n" << logofs_flush; + } + #endif + + return 1; +} + +int SetSendBuffer(int fd, int size) +{ + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to set SO_SNDBUF size to " + << size << " on FD#" << fd << ". Error is " + << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed to set SO_SNDBUF size to " + << size << " on FD#" << fd << ". Error is " + << EGET() << " '" << ESTR() << "'.\n"; + + return -1; + } + #ifdef TEST + else + { + *logofs << "Socket: Set SO_SNDBUF on FD#" << fd + << " to " << size << " bytes.\n" + << logofs_flush; + } + #endif + + return 1; +} + +int SetReceiveBuffer(int fd, int size) +{ + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to set SO_RCVBUF size to " + << size << " on FD#" << fd << ". Error is " + << EGET() << " '" << ESTR() << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed to set SO_RCVBUF size to " + << size << " on FD#" << fd << ". Error is " + << EGET() << " '" << ESTR() << "'.\n"; + + return -1; + } + #ifdef TEST + else + { + *logofs << "Socket: Set SO_RCVBUF on FD#" << fd + << " to " << size << " bytes.\n" + << logofs_flush; + } + #endif + + return 1; +} + +int SetNoDelay(int fd, int value) +{ + int result = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)); + + if (result == 0) + { + result = 1; + } + else if (result < 0) + { + // + // Is it become a different error on + // Mac OSX 10.4? + // + + #if defined(__APPLE__) + + result = 0; + + #endif + + #if defined(__sun) + + if (EGET() == ENOPROTOOPT) + { + result = 0; + } + + #endif + + #if !defined(__APPLE__) && !defined(__sun) + + if (EGET() == EOPNOTSUPP) + { + result = 0; + } + + #endif + } + + if (result < 0) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to set TCP_NODELAY flag on " + << "FD#" << fd << " to " << value << ". Error is " + << EGET() << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to set TCP_NODELAY flag on " + << "FD#" << fd << " to " << value << ". Error is " + << EGET() << " '" << ESTR() << "'.\n"; + } + #ifdef TEST + else if (result == 0) + { + #ifdef TEST + *logofs << "Socket: Option TCP_NODELAY not supported " + << "on FD#" << fd << ".\n" << logofs_flush; + #endif + } + else + { + *logofs << "Socket: Set TCP_NODELAY flag on FD#" + << fd << " to " << value << ".\n" + << logofs_flush; + } + #endif + + return result; +} + +int SetKeepAlive(int fd) +{ + int flag = 1; + + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag)) < 0) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to set SO_KEEPALIVE flag on " + << "FD#" << fd << ". Error is " << EGET() << " '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to set SO_KEEPALIVE flag on " + << "FD#" << fd << ". Error is " << EGET() << " '" + << ESTR() << "'.\n"; + + return -1; + } + #ifdef TEST + else + { + *logofs << "Socket: Set SO_KEEPALIVE flag on FD#" + << fd << ".\n" << logofs_flush; + } + #endif + + return 1; +} + +int SetLowDelay(int fd) +{ + if (_kernelStep < 0) + { + GetKernelStep(); + } + + switch (_kernelStep) + { + case 3: + case 2: + case 1: + { + int flag = IPTOS_LOWDELAY; + + if (setsockopt(fd, SOL_IP, IP_TOS, &flag, sizeof(flag)) < 0) + { + if (EGET() == EOPNOTSUPP) + { + #ifdef TEST + *logofs << "Socket: Option IPTOS_LOWDELAY not supported " + << "on FD#" << fd << ".\n" << logofs_flush; + #endif + + return 0; + } + else + { + #ifdef WARNING + *logofs << "Socket: WARNING! Failed to set IPTOS_LOWDELAY flag on " + << "FD#" << fd << ". Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Failed to set IPTOS_LOWDELAY flag on " + << "FD#" << fd << ". Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + return -1; + } + } + #ifdef TEST + else + { + *logofs << "Socket: Set IPTOS_LOWDELAY flag on FD#" + << fd << ".\n" << logofs_flush; + } + #endif + + return 1; + } + default: + { + #ifdef TEST + *logofs << "Socket: Option IPTOS_LOWDELAY not " + << "supported on FD#" << fd << ".\n" + << logofs_flush; + #endif + + return 0; + } + } +} + +int SetCloseOnExec(int fd) +{ + if (fcntl(fd, F_SETFD, 1) != 0) + { + #ifdef TEST + *logofs << "NXClient: PANIC! Cannot set close-on-exec " + << "on FD#" << fd << ". Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot set close-on-exec on FD#" + << fd << ". Error is " << EGET() << " '" << ESTR() + << "'.\n"; + + return -1; + } + + return 1; +} + +int GetBytesReadable(int fd) +{ + long readable = 0; + + // + // It may fail, for example at session + // shutdown. + // + + if (ioctl(fd, FIONREAD, &readable) < 0) + { + #ifdef TEST + *logofs << "Socket: PANIC! Failed to get bytes readable " + << "from FD#" << fd << ". Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + return -1; + } + + #ifdef TEST + *logofs << "Socket: Returning " << (int) readable + << " bytes readable on FD#" << fd << ".\n" + << logofs_flush; + #endif + + return (int) readable; +} + +int GetBytesWritable(int fd) +{ + if (_kernelStep < 0) + { + GetKernelStep(); + } + + long writable; + + switch (_kernelStep) + { + case 3: + { + // + // TODO: Should query the real size + // of the TCP write buffer. + // + + writable = 16384 - GetBytesQueued(fd); + + if (writable < 0) + { + writable = 0; + } + + break; + } + case 2: + { + if (ioctl(fd, TIOCOUTQ, (void *) &writable) < 0) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to get bytes writable " + << "on FD#" << fd << ". Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to get bytes writable " + << "on FD#" << fd << ". Error is " << EGET() + << " '" << ESTR() << "'.\n"; + + return -1; + } + + break; + } + default: + { + #ifdef TEST + *logofs << "Socket: Option TIOCOUTQ not supported " + << "on FD#" << fd << ",\n" << logofs_flush; + #endif + + // + // TODO: Should query the real size + // of the TCP write buffer. + // + + writable = 16384; + + break; + } + } + + #ifdef TEST + *logofs << "Socket: Returning " << writable + << " bytes writable on FD#" << fd + << ".\n" << logofs_flush; + #endif + + return (int) writable; +} + +int GetBytesQueued(int fd) +{ + // + // The TIOCOUTQ ioctl is not implemented on Cygwin + // and returns the space available on Linux Kernels + // 2.0 and 2.2 (like current MIPS for PS/2). + // + + if (_kernelStep < 0) + { + GetKernelStep(); + } + + long queued; + + switch (_kernelStep) + { + case 3: + { + if (ioctl(fd, TIOCOUTQ, (void *) &queued) < 0) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to get bytes queued " + << "on FD#" << fd << ". Error is " << EGET() + << " '" << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to get bytes queued " + << "on FD#" << fd << ". Error is " << EGET() + << " '" << ESTR() << "'.\n"; + + return -1; + } + + break; + } + case 2: + { + // + // TODO: Should query the real size + // of the TCP write buffer. + // + + queued = 16384 - GetBytesWritable(fd); + + if (queued < 0) + { + queued = 0; + } + + break; + } + default: + { + #ifdef TEST + *logofs << "Socket: Option TIOCOUTQ not supported " + << "on FD#" << fd << ",\n" << logofs_flush; + #endif + + queued = 0; + + break; + } + } + + #ifdef TEST + *logofs << "Socket: Returning " << queued + << " bytes queued on FD#" << fd + << ".\n" << logofs_flush; + #endif + + return (int) queued; +} + +int GetHostAddress(const char *name) +{ + hostent *host = gethostbyname(name); + + if (host == NULL) + { + // + // On some Unices gethostbyname() doesn't + // accept IP addresses, so try inet_addr. + // + + IN_ADDR_T address = inet_addr(name); + + if (address == INADDR_NONE) + { + #ifdef PANIC + *logofs << "Socket: PANIC! Failed to resolve address of '" + << name << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed to resolve address of '" + << name << "'.\n"; + + return 0; + } + + return (int) address; + } + else + { + return (*((int *) host -> h_addr_list[0])); + } +} diff --git a/nxcomp/src/Socket.h b/nxcomp/src/Socket.h new file mode 100644 index 000000000..5e7e47705 --- /dev/null +++ b/nxcomp/src/Socket.h @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Socket_H +#define Socket_H + +#include +#include +#include + +#ifdef __sun +#include +#include +#endif + +// +// Set socket options. +// + +int SetReuseAddress(int fd); +int SetNonBlocking(int fd, int value); +int SetLingerTimeout(int fd, int timeout); +int SetSendBuffer(int fd, int size); +int SetReceiveBuffer(int fd, int size); +int SetNoDelay(int fd, int value); +int SetKeepAlive(int fd); +int SetLowDelay(int fd); +int SetCloseOnExec(int fd); + +// +// Get kernel support level. +// + +int GetKernelStep(); + +// +// Get socket info. +// + +int GetBytesReadable(int fd); +int GetBytesWritable(int fd); +int GetBytesQueued(int fd); + +// +// Inline version, providing direct access +// to the interface. +// + +#include "Misc.h" + +inline int GetBytesReadable(int fd, int *readable) +{ + long t; + + int result = ioctl(fd, FIONREAD, &t); + + #ifdef DEBUG + *logofs << "Socket: Bytes readable from FD#" + << fd << " are " << t << " with result " + << result << ".\n" << logofs_flush; + #endif + + *readable = (int) t; + + return result; +} + +// +// Query Internet address. +// + +int GetHostAddress(const char *name); + +#endif /* Socket_H */ diff --git a/nxcomp/src/Split.cpp b/nxcomp/src/Split.cpp new file mode 100644 index 000000000..e2fea97cc --- /dev/null +++ b/nxcomp/src/Split.cpp @@ -0,0 +1,1839 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "Misc.h" + +#include "Split.h" + +#include "Control.h" +#include "Statistics.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "StaticCompressor.h" + +#include "Unpack.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Define this to trace elements +// allocated and deallocated. +// + +#undef REFERENCES + +// +// Counters used for store control. +// + +int SplitStore::totalSplitSize_; +int SplitStore::totalSplitStorageSize_; + +// +// This is used for reference count. +// + +#ifdef REFERENCES + +int Split::references_ = 0; + +#endif + +Split::Split() +{ + resource_ = nothing; + position_ = nothing; + + store_ = NULL; + + d_size_ = 0; + i_size_ = 0; + c_size_ = 0; + r_size_ = 0; + + next_ = 0; + load_ = 0; + save_ = 0; + + checksum_ = NULL; + state_ = split_undefined; + mode_ = split_none; + action_ = is_discarded; + + #ifdef REFERENCES + + references_++; + + *logofs << "Split: Created new Split at " + << this << " out of " << references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +Split::~Split() +{ + delete [] checksum_; + + #ifdef REFERENCES + + references_--; + + *logofs << "Split: Deleted Split at " + << this << " out of " << references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +SplitStore::SplitStore(StaticCompressor *compressor, CommitStore *commits, int resource) + + : compressor_(compressor), commits_(commits), resource_(resource) +{ + splits_ = new T_splits(); + + current_ = splits_ -> end(); + + splitStorageSize_ = 0; + + #ifdef TEST + *logofs << "SplitStore: Created new store ["; + + if (resource_ != nothing) + { + *logofs << resource_; + } + else + { + *logofs << "commit"; + } + + *logofs << "].\n" << logofs_flush; + + *logofs << "SplitStore: Total messages in stores are " + << totalSplitSize_ << " with total storage size " + << totalSplitStorageSize_ << ".\n" + << logofs_flush; + #endif +} + +SplitStore::~SplitStore() +{ + totalSplitSize_ -= splits_ -> size(); + + totalSplitStorageSize_ -= splitStorageSize_; + + for (T_splits::iterator i = splits_ -> begin(); + i != splits_ -> end(); i++) + { + delete *i; + } + + delete splits_; + + #ifdef TEST + *logofs << "SplitStore: Deleted store ["; + + if (resource_ != nothing) + { + *logofs << resource_; + } + else + { + *logofs << "commit"; + } + + *logofs << "] with storage size " << splitStorageSize_ + << ".\n" << logofs_flush; + + *logofs << "SplitStore: Total messages in stores are " + << totalSplitSize_ << " with total storage size " + << totalSplitStorageSize_ << ".\n" + << logofs_flush; + #endif +} + +// +// This is called at the encoding side. +// + +Split *SplitStore::add(MessageStore *store, int resource, T_split_mode mode, + int position, T_store_action action, T_checksum checksum, + const unsigned char *buffer, const int size) +{ + #ifdef TEST + *logofs << "SplitStore: Adding message [" << (unsigned int) store -> + opcode() << "] resource " << resource << " mode " << mode + << " position " << position << " action [" << DumpAction(action) + << "] and checksum [" << DumpChecksum(checksum) << "]" + << ".\n" << logofs_flush; + #endif + + Split *split = new Split(); + + if (split == NULL) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Can't allocate " + << "memory for the split.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory " + << "for the split.\n"; + + HandleAbort(); + } + + split -> store_ = store; + split -> resource_ = resource; + split -> mode_ = mode; + split -> position_ = position; + split -> action_ = action; + + split -> store_ -> validateSize(size); + + // + // The checksum is not provided if the + // message is cached. + // + + if (checksum != NULL) + { + split -> checksum_ = new md5_byte_t[MD5_LENGTH]; + + memcpy(split -> checksum_, checksum, MD5_LENGTH); + } + + // + // We don't need the identity data at the + // encoding side. This qualifies the split + // as a split generated at the encoding + // side. + // + + split -> i_size_ = store -> identitySize(buffer, size); + + split -> d_size_ = size - split -> i_size_; + + if (action == IS_ADDED || action == is_discarded) + { + // + // If the message was added to message + // store or discarded we need to save + // the real data so we can transfer it + // at later time. + // + + split -> data_.resize(split -> d_size_); + + memcpy(split -> data_.begin(), buffer + split -> i_size_, split -> d_size_); + + // + // If the message was added, lock it so + // it will not be used by the encoding + // side until it is recomposed. + // + + if (action == IS_ADDED) + { + split -> store_ -> lock(split -> position_); + + #ifdef TEST + + commits_ -> validate(split); + + #endif + } + } + #ifdef WARNING + else + { + *logofs << "SplitStore: WARNING! Not copying data for the cached message.\n" + << logofs_flush; + } + #endif + + push(split); + + return split; +} + +// +// This is called at decoding side. If checksum +// is provided, the message can be searched on +// disk, then, if message is found, an event is +// sent to abort the data transfer. +// + +Split *SplitStore::add(MessageStore *store, int resource, int position, + T_store_action action, T_checksum checksum, + unsigned char *buffer, const int size) +{ + #ifdef TEST + *logofs << "SplitStore: Adding message [" + << (unsigned int) store -> opcode() << "] resource " + << resource << " position " << position << " action [" + << DumpAction(action) << "] and checksum [" + << DumpChecksum(checksum) << "].\n" << logofs_flush; + #endif + + Split *split = new Split(); + + if (split == NULL) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Can't allocate " + << "memory for the split.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory " + << "for the split.\n"; + + HandleAbort(); + } + + split -> store_ = store; + split -> resource_ = resource; + split -> position_ = position; + split -> action_ = action; + + split -> store_ -> validateSize(size); + + // + // Check if the checksum was provided + // by the remote. + // + + if (checksum != NULL) + { + split -> checksum_ = new md5_byte_t[MD5_LENGTH]; + + memcpy(split -> checksum_, checksum, MD5_LENGTH); + } + + split -> i_size_ = store -> identitySize(buffer, size); + + // + // Copy the identity so we can expand the + // message when it is committed. + // + + split -> identity_.resize(split -> i_size_); + + memcpy(split -> identity_.begin(), buffer, split -> i_size_); + + split -> d_size_ = size - split -> i_size_; + + if (action == IS_ADDED || action == is_discarded) + { + // + // The unpack procedure will check if the + // first 2 bytes of the buffer contain the + // pattern and will not try to expand the + // image. + // + + split -> data_.resize(2); + + unsigned char *data = split -> data_.begin(); + + data[0] = SPLIT_PATTERN; + data[1] = SPLIT_PATTERN; + + // + // If the message was added to the store, + // we don't have the data part, yet, so + // we need to lock the message until it + // is recomposed. + // + + if (action == IS_ADDED) + { + split -> store_ -> lock(split -> position_); + + #ifdef TEST + + commits_ -> validate(split); + + #endif + } + } + else + { + #ifdef WARNING + *logofs << "SplitStore: WARNING! Copying data for the cached message.\n" + << logofs_flush; + #endif + + // + // We may optionally take the data from the + // message store in compressed form, but, + // as the data has been decompressed in the + // buffer, we save a further decompression. + // + + split -> data_.resize(split -> d_size_); + + memcpy(split -> data_.begin(), buffer + split -> i_size_, split -> d_size_); + } + + push(split); + + return split; +} + +void SplitStore::push(Split *split) +{ + splits_ -> push_back(split); + + splitStorageSize_ += getNodeSize(split); + + totalSplitSize_++; + + totalSplitStorageSize_ += getNodeSize(split); + + statistics -> addSplit(); + + #ifdef TEST + *logofs << "SplitStore: There are " << splits_ -> size() + << " messages in store [" << resource_ << "] with " + << "storage size " << splitStorageSize_ << ".\n" + << logofs_flush; + + *logofs << "SplitStore: Total messages in stores are " + << totalSplitSize_ << " with total storage size " + << totalSplitStorageSize_ << ".\n" + << logofs_flush; + #endif + + split -> state_ = split_added; +} + +void SplitStore::dump() +{ + #ifdef DUMP + + int n; + + Split *split; + + *logofs << "SplitStore: DUMP! Dumping content of "; + + if (commits_ == NULL) + { + *logofs << "[commits]"; + } + else + { + *logofs << "[splits] for store [" << resource_ << "]"; + } + + *logofs << " with [" << getSize() << "] elements " + << "in the store.\n" << logofs_flush; + + n = 0; + + for (T_splits::iterator i = splits_ -> begin(); i != splits_ -> end(); i++, n++) + { + split = *i; + + *logofs << "SplitStore: DUMP! Split [" << n << "] has action [" + << DumpAction(split -> action_) << "] state [" + << DumpState(split -> state_) << "] "; + + if (split -> resource_ >= 0) + { + *logofs << "resource " << split -> resource_; + } + + *logofs << " request " << (unsigned) split -> store_ -> opcode() + << " position " << split -> position_ << " size is " + << split -> data_.size() << " (" << split -> d_size_ + << "/" << split -> c_size_ << "/" << split -> r_size_ + << ") with " << split -> data_.size() - split -> next_ + << "] bytes to go.\n" << logofs_flush; + } + + #endif +} + +int SplitStore::send(EncodeBuffer &encodeBuffer, int packetSize) +{ + if (splits_ -> size() == 0) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Function send called with no splits available.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Function send called with no splits available.\n"; + + HandleAbort(); + } + + // + // A start operation must always be executed on + // the split, even in the case the split will be + // later aborted. + // + + if (current_ == splits_ -> end()) + { + start(encodeBuffer); + } + + // + // If we have matched the checksum received from + // the remote side then we must abort the current + // split, else we can send another block of data + // to the remote peer. + // + + Split *split = *current_; + + unsigned int abort = 0; + + if (split -> state_ == split_loaded) + { + abort = 1; + } + + encodeBuffer.encodeBoolValue(abort); + + if (abort == 1) + { + #ifdef TEST + *logofs << "SplitStore: Aborting split for checksum [" + << DumpChecksum(split -> checksum_) << "] position " + << split -> position_ << " with " << (split -> + data_.size() - split -> next_) << " bytes to go " + << "out of " << split -> data_.size() + << ".\n" << logofs_flush; + #endif + + statistics -> addSplitAborted(); + + statistics -> addSplitAbortedBytesOut(split -> data_.size() - split -> next_); + + split -> next_ = split -> data_.size(); + + split -> state_ = split_aborted; + } + else + { + int count = (packetSize <= 0 || split -> next_ + + packetSize > (int) split -> data_.size() ? + split -> data_.size() - split -> next_ : packetSize); + + #ifdef TEST + *logofs << "SplitStore: Sending split for checksum [" + << DumpChecksum(split -> checksum_) << "] count " + << count << " position " << split -> position_ + << ". Data size is " << split -> data_.size() << " (" + << split -> d_size_ << "/" << split -> c_size_ << "), " + << split -> data_.size() - (split -> next_ + count) + << " to go.\n" << logofs_flush; + #endif + + encodeBuffer.encodeValue(count, 32, 10); + + encodeBuffer.encodeMemory(split -> data_.begin() + split -> next_, count); + + split -> next_ += count; + } + + // + // Was data completely transferred? We are the + // sending side. We must update the message in + // store, even if split was aborted. + // + + if (split -> next_ != ((int) split -> data_.size())) + { + return 0; + } + + // + // Move the split at the head of the + // list to the commits. + // + + remove(split); + + // + // Reset current position to the + // end of repository. + // + + current_ = splits_ -> end(); + + #ifdef TEST + *logofs << "SplitStore: Removed split at head of the list. " + << "Resource is " << split -> resource_ << " request " + << (unsigned) split -> store_ -> opcode() << " position " + << split -> position_ << ".\n" << logofs_flush; + #endif + + return 1; +} + +int SplitStore::start(EncodeBuffer &encodeBuffer) +{ + // + // Get the element at the top of the + // list. + // + + current_ = splits_ -> begin(); + + Split *split = *current_; + + #ifdef TEST + *logofs << "SplitStore: Starting split for checksum [" + << DumpChecksum(split -> checksum_) << "] position " + << split -> position_ << " with " << (split -> + data_.size() - split -> next_) << " bytes to go " + << "out of " << split -> data_.size() + << ".\n" << logofs_flush; + #endif + + // + // See if compression of the data part is + // enabled. + // + + if (split -> store_ -> enableCompress) + { + // + // If the split is going to be aborted don't + // compress the data and go straight to the + // send. The new data size will be assumed + // from the disk cache. + // + + if (split -> state_ != split_loaded) + { + unsigned int compressedSize = 0; + unsigned char *compressedData = NULL; + + if (control -> LocalDataCompression && + (compressor_ -> compressBuffer(split -> data_.begin(), split -> d_size_, + compressedData, compressedSize))) + { + // + // Replace the data with the one in + // compressed form. + // + + #ifdef TEST + *logofs << "SplitStore: Split data of size " << split -> d_size_ + << " has been compressed to " << compressedSize + << " bytes.\n" << logofs_flush; + #endif + + split -> data_.clear(); + + split -> data_.resize(compressedSize); + + memcpy(split -> data_.begin(), compressedData, compressedSize); + + split -> c_size_ = compressedSize; + + // + // Inform our peer that the data is + // compressed and send the new size. + // + + encodeBuffer.encodeBoolValue(1); + + encodeBuffer.encodeValue(compressedSize, 32, 14); + + #ifdef TEST + *logofs << "SplitStore: Signaled " << split -> c_size_ + << " bytes of compressed data for this message.\n" + << logofs_flush; + #endif + + return 1; + } + } + #ifdef TEST + else + { + *logofs << "SplitStore: Not trying to compress the " + << "loaded message.\n" << logofs_flush; + } + #endif + + // + // Tell to the remote that data will + // follow uncompressed. + // + + encodeBuffer.encodeBoolValue(0); + } + + return 1; +} + +int SplitStore::start(DecodeBuffer &decodeBuffer) +{ + #ifdef TEST + *logofs << "SplitStore: Going to receive a new split from the remote side.\n" + << logofs_flush; + #endif + + // + // Get the element at the head + // of the list. + // + + current_ = splits_ -> begin(); + + Split *split = *current_; + + unsigned int compressedSize = 0; + + // + // Save the data size known by the remote. + // This information will be needed if the + // remote will not have a chance to abort + // the split. + // + + split -> r_size_ = split -> d_size_; + + // + // Find out if data was compressed by the + // remote. + // + + if (split -> store_ -> enableCompress) + { + decodeBuffer.decodeBoolValue(compressedSize); + + if (compressedSize == 1) + { + // + // Get the compressed size. + // + + // Since ProtoStep7 (#issue 108) + decodeBuffer.decodeValue(compressedSize, 32, 14); + + split -> store_ -> validateSize(split -> d_size_, compressedSize); + + split -> r_size_ = compressedSize; + } + } + + // + // Update the size if the split + // was not already loaded. + // + + if (split -> state_ != split_loaded) + { + split -> data_.clear(); + + if (compressedSize > 0) + { + split -> c_size_ = compressedSize; + + #ifdef TEST + *logofs << "SplitStore: Split data of size " + << split -> d_size_ << " was compressed to " + << split -> c_size_ << " bytes.\n" + << logofs_flush; + #endif + + split -> data_.resize(split -> c_size_); + } + else + { + split -> data_.resize(split -> d_size_); + } + + unsigned char *data = split -> data_.begin(); + + data[0] = SPLIT_PATTERN; + data[1] = SPLIT_PATTERN; + } + #ifdef TEST + else + { + // + // The message had been already + // loaded from disk. + // + + if (compressedSize > 0) + { + if ((int) compressedSize != split -> c_size_) + { + *logofs << "SplitStore: WARNING! Compressed data size is " + << "different than the loaded compressed size.\n" + << logofs_flush; + } + + *logofs << "SplitStore: Ignoring the new size with " + << "loaded compressed size " << split -> c_size_ + << ".\n" << logofs_flush; + } + } + #endif + + return 1; +} + +int SplitStore::receive(DecodeBuffer &decodeBuffer) +{ + if (splits_ -> size() == 0) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Function receive called with no splits available.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Function receive called with no splits available.\n"; + + HandleAbort(); + } + + if (current_ == splits_ -> end()) + { + start(decodeBuffer); + } + + // + // Check first if split was aborted, else add + // any new data to message being recomposed. + // + + Split *split = *current_; + + unsigned int abort = 0; + + decodeBuffer.decodeBoolValue(abort); + + if (abort == 1) + { + #ifdef TEST + *logofs << "SplitStore: Aborting split for checksum [" + << DumpChecksum(split -> checksum_) << "] position " + << split -> position_ << " with " << (split -> + data_.size() - split -> next_) << " bytes to go " + << "out of " << split -> data_.size() + << ".\n" << logofs_flush; + #endif + + statistics -> addSplitAborted(); + + statistics -> addSplitAbortedBytesOut(split -> r_size_ - split -> next_); + + split -> next_ = split -> r_size_; + + split -> state_ = split_aborted; + } + else + { + // + // Get the size of the packet. + // + + unsigned int count; + + decodeBuffer.decodeValue(count, 32, 10); + + // + // If the split was not already loaded from + // disk, decode the packet and update our + // copy of the data. The encoding side may + // have not received the abort event, yet, + // and may be unaware that the message is + // stored in compressed form at our side. + // + + #ifdef TEST + *logofs << "SplitStore: Receiving split for checksum [" + << DumpChecksum(split -> checksum_) << "] count " + << count << " position " << split -> position_ + << ". Data size is " << split -> data_.size() << " (" + << split -> d_size_ << "/" << split -> c_size_ << "/" + << split -> r_size_ << "), " << split -> r_size_ - + (split -> next_ + count) << " to go.\n" + << logofs_flush; + #endif + + if (split -> next_ + count > (unsigned) split -> r_size_) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Invalid data count " + << count << "provided in the split.\n" + << logofs_flush; + + *logofs << "SplitStore: PANIC! While receiving split for " + << "checksum [" << DumpChecksum(split -> checksum_) + << "] with count " << count << " action [" + << DumpAction(split -> action_) << "] state [" + << DumpState(split -> state_) << "]. Data size is " + << split -> data_.size() << " (" << split -> d_size_ + << "/" << split -> c_size_ << "), " << split -> + data_.size() - (split -> next_ + count) + << " to go.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid data count " + << count << "provided in the split.\n"; + + HandleAbort(); + } + + if (split -> state_ != split_loaded) + { + #ifdef TEST + + if (split -> next_ + count > split -> data_.size()) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Inconsistent split data size " + << split -> data_.size() << " with expected size " + << split -> r_size_ << ".\n" + << logofs_flush; + #endif + + HandleAbort(); + } + + #endif + + memcpy(split -> data_.begin() + split -> next_, + decodeBuffer.decodeMemory(count), count); + } + else + { + #ifdef TEST + *logofs << "SplitStore: WARNING! Data discarded with split " + << "loaded from disk.\n" << logofs_flush; + #endif + + decodeBuffer.decodeMemory(count); + } + + split -> next_ += count; + } + + // + // Is unsplit complete? + // + + if (split -> next_ != split -> r_size_) + { + return 0; + } + + // + // If the persistent cache is enabled, + // we have a valid checksum and the + // split was not originally retrieved + // from disk, save the message on disk. + // + + if (split -> state_ != split_loaded && + split -> state_ != split_aborted) + { + save(split); + } + + // + // Move the split at the head of the + // list to the commits. + // + + remove(split); + + // + // Reset the current position to the + // end of the repository. + // + + current_ = splits_ -> end(); + + #ifdef TEST + *logofs << "SplitStore: Removed split at head of the list. " + << "Resource is " << split -> resource_ << " request " + << (unsigned) split -> store_ -> opcode() << " position " + << split -> position_ << ".\n" << logofs_flush; + #endif + + return 1; +} + +Split *SplitStore::pop() +{ + if (splits_ -> size() == 0) + { + #ifdef TEST + *logofs << "SplitStore: The split store is empty.\n" + << logofs_flush; + #endif + + return NULL; + } + + // + // Move the pointer at the end of the list. + // The next send operation will eventually + // start a new split. + // + + current_ = splits_ -> end(); + + Split *split = *(splits_ -> begin()); + + splits_ -> pop_front(); + + #ifdef TEST + *logofs << "SplitStore: Removed split at the head of the " + << "list with resource " << split -> resource_ + << " request " << (unsigned) split -> store_ -> + opcode() << " position " << split -> position_ + << ".\n" << logofs_flush; + #endif + + splitStorageSize_ -= getNodeSize(split); + + totalSplitSize_--; + + totalSplitStorageSize_ -= getNodeSize(split); + + #ifdef TEST + *logofs << "SplitStore: There are " << splits_ -> size() + << " messages in store [" << resource_ << "] with " + << "storage size " << splitStorageSize_ << ".\n" + << logofs_flush; + + *logofs << "SplitStore: Total messages in stores are " + << totalSplitSize_ << " with total storage size " + << totalSplitStorageSize_ << ".\n" + << logofs_flush; + #endif + + return split; +} + +void SplitStore::remove(Split *split) +{ + #ifdef TEST + *logofs << "SplitStore: Going to remove the split from the list.\n" + << logofs_flush; + #endif + + #ifdef TEST + + if (split != getFirstSplit()) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Trying to remove a split " + << "not at the head of the list.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Trying to remove a split " + << "not at the head of the list.\n"; + + HandleAbort(); + } + + #endif + + // + // Move the split to the commit store. + // + + splits_ -> pop_front(); + + commits_ -> splits_ -> push_back(split); + + splitStorageSize_ -= getNodeSize(split); + + totalSplitSize_--; + + totalSplitStorageSize_ -= getNodeSize(split); + + #ifdef TEST + *logofs << "SplitStore: There are " << splits_ -> size() + << " messages in store [" << resource_ << "] with " + << "storage size " << splitStorageSize_ << ".\n" + << logofs_flush; + + *logofs << "SplitStore: Total messages in stores are " + << totalSplitSize_ << " with total storage size " + << totalSplitStorageSize_ << ".\n" + << logofs_flush; + #endif + + #ifdef TEST + + if (splits_ -> size() == 0) + { + if (splitStorageSize_ != 0) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Internal error calculating " + << "split data size. It is " << splitStorageSize_ + << " while should be 0.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Internal error calculating " + << "split data size. It is " << splitStorageSize_ + << " while should be 0.\n"; + + HandleAbort(); + } + } + + #endif +} + +const char *SplitStore::name(const T_checksum checksum) +{ + if (checksum == NULL) + { + return NULL; + } + + char *pathName = control -> ImageCachePath; + + if (pathName == NULL) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Cannot determine directory of " + << "NX image files.\n" << logofs_flush; + #endif + + return NULL; + } + + int pathSize = strlen(pathName); + + // + // File name is "[path][/I-c/I-][checksum][\0]", + // where c is the first hex digit of checksum. + // + + int nameSize = pathSize + 7 + MD5_LENGTH * 2 + 1; + + char *fileName = new char[nameSize]; + + if (fileName == NULL) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Cannot allocate space for " + << "NX image file name.\n" << logofs_flush; + #endif + + return NULL; + } + + strcpy(fileName, pathName); + + sprintf(fileName + pathSize, "/I-%1X/I-", + *((unsigned char *) checksum) >> 4); + + for (unsigned int i = 0; i < MD5_LENGTH; i++) + { + sprintf(fileName + pathSize + 7 + (i * 2), "%02X", + ((unsigned char *) checksum)[i]); + } + + return fileName; +} + +int SplitStore::save(Split *split) +{ + // + // Check if saving the message on the + // persistent cache is enabled. + // + + if (split -> save_ == 0) + { + return 0; + } + + T_checksum checksum = split -> checksum_; + + const char *fileName = name(checksum); + + if (fileName == NULL) + { + return 0; + } + + unsigned int splitSize; + + ostream *fileStream = NULL; + + unsigned char *fileHeader = NULL; + + // + // Get the other data from the split. + // + + unsigned char opcode = split -> store_ -> opcode(); + + unsigned char *data = split -> data_.begin(); + + int dataSize = split -> d_size_; + int compressedSize = split -> c_size_; + + #ifdef DEBUG + *logofs << "SplitStore: Going to save split OPCODE#" + << (unsigned int) opcode << " to file '" << fileName + << "' with size " << dataSize << " and compressed size " + << compressedSize << ".\n" << logofs_flush; + #endif + + DisableSignals(); + + // + // Change the mask to make the file only + // readable by the user, then restore the + // old mask. + // + + mode_t fileMode; + + // + // Check if the file already exists. We try to + // load the message when the split is started + // and save it only if it is not found. Still + // the remote side may send the same image mul- + // tiple time and we may not have the time to + // notify the abort. + // + + struct stat fileStat; + + if (stat(fileName, &fileStat) == 0) + { + #ifdef TEST + *logofs << "SplitStore: Image file '" << fileName + << "' already present on disk.\n" + << logofs_flush; + #endif + + goto SplitStoreSaveError; + } + + fileMode = umask(0077); + + fileStream = new ofstream(fileName, ios::out | ios::binary); + + umask(fileMode); + + if (CheckData(fileStream) < 0) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Cannot open file '" << fileName + << "' for output.\n" << logofs_flush; + #endif + + goto SplitStoreSaveError; + } + + fileHeader = new unsigned char[SPLIT_HEADER_SIZE]; + + if (fileHeader == NULL) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Cannot allocate space for " + << "NX image header.\n" << logofs_flush; + #endif + + goto SplitStoreSaveError; + } + + // + // Leave 3 bytes for future use. Please note + // that, on some CPUs, we can't use PutULONG() + // to write integers that are not aligned to + // the word boundary. + // + + *fileHeader = opcode; + + *(fileHeader + 1) = 0; + *(fileHeader + 2) = 0; + *(fileHeader + 3) = 0; + + PutULONG(dataSize, fileHeader + 4, false); + PutULONG(compressedSize, fileHeader + 8, false); + + splitSize = (compressedSize > 0 ? compressedSize : dataSize); + + if (PutData(fileStream, fileHeader, SPLIT_HEADER_SIZE) < 0 || + PutData(fileStream, data, splitSize) < 0) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Cannot write to NX " + << "image file '" << fileName << "'.\n" + << logofs_flush; + #endif + + goto SplitStoreSaveError; + } + + // + // Check if all the data was written on the + // disk and, if not, remove the faulty copy. + // + + FlushData(fileStream); + + if (CheckData(fileStream) < 0) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Failed to write NX " + << "image file '" << fileName << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Failed to write NX " + << "image file '" << fileName << "'.\n"; + + goto SplitStoreSaveError; + } + + #ifdef TEST + *logofs << "SplitStore: Saved split to file '" << fileName + << "' with data size " << dataSize << " and " + << "compressed data size " << compressedSize + << ".\n" << logofs_flush; + #endif + + delete fileStream; + + delete [] fileName; + delete [] fileHeader; + + EnableSignals(); + + // + // Update the timestamp as the operation + // may have taken some time. + // + + getNewTimestamp(); + + return 1; + +SplitStoreSaveError: + + delete fileStream; + + if (fileName != NULL) + { + unlink(fileName); + } + + delete [] fileName; + delete [] fileHeader; + + EnableSignals(); + + return -1; +} + +int SplitStore::find(Split *split) +{ + const char *fileName = name(split -> checksum_); + + if (fileName == NULL) + { + return 0; + } + + #ifdef DEBUG + *logofs << "SplitStore: Going to find split OPCODE#" + << (unsigned) split -> store_ -> opcode() + << " in file '" << fileName << "'.\n" + << logofs_flush; + #endif + + // + // Check if the file exists and, at the + // same time, update the modification + // time to prevent its deletion. + // + + if (utime(fileName, NULL) == 0) + { + #ifdef TEST + *logofs << "SplitStore: Found split OPCODE#" + << (unsigned) split -> store_ -> opcode() + << " in file '" << fileName << "'.\n" + << logofs_flush; + #endif + + delete [] fileName; + + return 1; + } + + #ifdef TEST + *logofs << "SplitStore: WARNING! Can't find split " + << "OPCODE#" << (unsigned) split -> store_ -> + opcode() << " in file '" << fileName + << "'.\n" << logofs_flush; + #endif + + delete [] fileName; + + return 0; +} + +int SplitStore::load(Split *split) +{ + // + // Check if loading the image is enabled. + // + + if (split -> load_ == 0) + { + return 0; + } + + const char *fileName = name(split -> checksum_); + + if (fileName == NULL) + { + return 0; + } + + unsigned char fileOpcode; + + int fileSize; + int fileCSize; + + istream *fileStream = NULL; + + unsigned char *fileHeader = NULL; + + DisableSignals(); + + #ifdef DEBUG + *logofs << "SplitStore: Going to load split OPCODE#" + << (unsigned int) split -> store_ -> opcode() + << " from file '" << fileName << "'.\n" + << logofs_flush; + #endif + + fileStream = new ifstream(fileName, ios::in | ios::binary); + + if (CheckData(fileStream) < 0) + { + #ifdef TEST + *logofs << "SplitStore: WARNING! Can't open image file '" + << fileName << "' on disk.\n" << logofs_flush; + #endif + + goto SplitStoreLoadError; + } + + fileHeader = new unsigned char[SPLIT_HEADER_SIZE]; + + if (fileHeader == NULL) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Cannot allocate space for " + << "NX image header.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot allocate space for " + << "NX image header.\n"; + + goto SplitStoreLoadError; + } + + if (GetData(fileStream, fileHeader, SPLIT_HEADER_SIZE) < 0) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Cannot read header from " + << "NX image file '" << fileName << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Cannot read header from " + << "NX image file '" << fileName << "'.\n"; + + goto SplitStoreLoadError; + } + + fileOpcode = *fileHeader; + + fileSize = GetULONG(fileHeader + 4, false); + fileCSize = GetULONG(fileHeader + 8, false); + + // + // Don't complain if we find that data was saved + // in compressed form even if we were not aware + // of the compressed data size. The remote side + // compresses the data only at the time it starts + // the transferral of the split. We replace our + // copy of the data with whatever we find on the + // disk. + // + + if (fileOpcode != split -> store_ -> opcode() || + fileSize != split -> d_size_ || + fileSize > control -> MaximumRequestSize || + fileCSize > control -> MaximumRequestSize) + + { + #ifdef TEST + *logofs << "SplitStore: PANIC! Corrupted image file '" << fileName + << "'. Expected " << (unsigned int) split -> store_ -> opcode() + << "/" << split -> d_size_ << "/" << split -> c_size_ << " found " + << (unsigned int) fileOpcode << "/" << fileSize << "/" + << fileCSize << ".\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Corrupted image file '" << fileName + << "'. Expected " << (unsigned int) split -> store_ -> opcode() + << "/" << split -> d_size_ << "/" << split -> c_size_ << " found " + << (unsigned int) fileOpcode << "/" << fileSize << "/" + << fileCSize << ".\n"; + + goto SplitStoreLoadError; + } + + // + // Update the data size with the size + // we got from the disk record. + // + + split -> d_size_ = fileSize; + split -> c_size_ = fileCSize; + + unsigned int splitSize; + + if (fileCSize > 0) + { + splitSize = fileCSize; + } + else + { + splitSize = fileSize; + } + + // + // Allocate a new buffer if we didn't + // do that already or if the size is + // different. + // + + if (split -> data_.size() != splitSize) + { + split -> data_.clear(); + + split -> data_.resize(splitSize); + } + + if (GetData(fileStream, split -> data_.begin(), splitSize) < 0) + { + #ifdef PANIC + *logofs << "SplitStore: PANIC! Cannot read data from " + << "NX image file '" << fileName << "'.\n" + << logofs_flush; + #endif + + cerr << "Warning" << ": Cannot read data from " + << "NX image file '" << fileName << "'.\n"; + + goto SplitStoreLoadError; + } + + delete fileStream; + + delete [] fileHeader; + delete [] fileName; + + EnableSignals(); + + // + // Update the timestamp as the operation + // may have taken some time. + // + + getNewTimestamp(); + + return 1; + +SplitStoreLoadError: + + delete fileStream; + + unlink(fileName); + + delete [] fileName; + delete [] fileHeader; + + EnableSignals(); + + return -1; +} + +Split *CommitStore::pop() +{ + if (splits_ -> size() == 0) + { + #ifdef TEST + *logofs << "CommitStore: The commit store is empty.\n" + << logofs_flush; + #endif + + return NULL; + } + + Split *split = *(splits_ -> begin()); + + splits_ -> pop_front(); + + #ifdef TEST + *logofs << "CommitStore: Removed commit split at the head " + << "of the list with resource " << split -> resource_ + << " request " << (unsigned) split -> store_ -> + opcode() << " position " << split -> position_ + << ".\n" << logofs_flush; + #endif + + return split; +} + +int CommitStore::expand(Split *split, unsigned char *buffer, const int size) +{ + #ifdef TEST + *logofs << "CommitStore: Expanding split data with " + << size << " bytes to write.\n" + << logofs_flush; + #endif + + #ifdef TEST + + if (size < split -> i_size_ + split -> d_size_) + { + #ifdef PANIC + *logofs << "CommitStore: PANIC! Wrong size of the provided " + << "buffer. It should be " << split -> i_size_ + + split -> d_size_ << " instead of " << size + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Wrong size of the provided " + << "buffer. It should be " << split -> i_size_ + + split -> d_size_ << " instead of " << size + << ".\n"; + + HandleAbort(); + } + + #endif + + #ifdef DEBUG + *logofs << "CommitStore: Copying " << split -> i_size_ + << " bytes of identity.\n" << logofs_flush; + #endif + + memcpy(buffer, split -> identity_.begin(), split -> i_size_); + + // + // Copy data, if any, to the buffer. + // + + if (size > split -> i_size_) + { + // + // Check if message has been stored + // in compressed format. + // + + if (split -> c_size_ == 0) + { + #ifdef DEBUG + *logofs << "CommitStore: Copying " << split -> d_size_ + << " bytes of plain data.\n" << logofs_flush; + #endif + + memcpy(buffer + split -> i_size_, split -> data_.begin(), split -> d_size_); + } + else + { + #ifdef DEBUG + *logofs << "CommitStore: Decompressing " << split -> c_size_ + << " bytes and copying " << split -> d_size_ + << " bytes of data.\n" << logofs_flush; + #endif + + if (compressor_ -> + decompressBuffer(buffer + split -> i_size_, + split -> d_size_, split -> data_.begin(), + split -> c_size_) < 0) + { + #ifdef PANIC + *logofs << "CommitStore: PANIC! Split data decompression failed.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Split data decompression failed.\n"; + + return -1; + } + } + } + + return 1; +} + +int CommitStore::update(Split *split) +{ + if (split -> action_ != IS_ADDED) + { + return 0; + } + + // + // We don't need the identity data at + // the encoding side. + // + + if (split -> identity_.size() == 0) + { + #ifdef TEST + *logofs << "SplitStore: Going to update the size " + << "for object at position " << split -> position_ + << " with data size " << split -> d_size_ + << " and compressed data size " << split -> + c_size_ << ".\n" << logofs_flush; + #endif + + split -> store_ -> updateData(split -> position_, split -> d_size_, + split -> c_size_); + } + else + { + #ifdef TEST + *logofs << "SplitStore: Going to update data and size " + << "for object at position " << split -> position_ + << " with data size " << split -> d_size_ + << " and compressed data size " << split -> + c_size_ << ".\n" << logofs_flush; + #endif + + split -> store_ -> updateData(split -> position_, split -> data_.begin(), + split -> d_size_, split -> c_size_); + } + + // + // Unlock message so that we can remove + // or save it on disk at shutdown. + // + + if (split -> action_ == IS_ADDED) + { + split -> store_ -> unlock(split -> position_); + + #ifdef TEST + + validate(split); + + #endif + } + + return 1; +} + +int CommitStore::validate(Split *split) +{ + MessageStore *store = split -> store_; + + int p, n, s; + + s = store -> cacheSlots; + + for (p = 0, n = 0; p < s; p++) + { + if (store -> getLocks(p) == 1) + { + n++; + } + else if (store -> getLocks(p) != 0) + { + #ifdef PANIC + *logofs << "CommitStore: PANIC! Repository for OPCODE#" + << (unsigned int) store -> opcode() << " has " + << store -> getLocks(p) << " locks for message " + << "at position " << p << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Repository for OPCODE#" + << (unsigned int) store -> opcode() << " has " + << store -> getLocks(p) << " locks for message " + << "at position " << p << ".\n"; + + HandleAbort(); + } + } + + #ifdef TEST + *logofs << "CommitStore: Repository for OPCODE#" + << (unsigned int) store -> opcode() + << " has " << n << " locked messages.\n" + << logofs_flush; + #endif + + return 1; +} diff --git a/nxcomp/src/Split.h b/nxcomp/src/Split.h new file mode 100644 index 000000000..ee5eae7fe --- /dev/null +++ b/nxcomp/src/Split.h @@ -0,0 +1,543 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Split_H +#define Split_H + +#include "Types.h" +#include "Timestamp.h" +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Define this to know how many splits +// are allocated and deallocated. +// + +#undef REFERENCES + +// +// Size of header of messages saved on +// disk. +// + +#define SPLIT_HEADER_SIZE 12 + +// +// This class is used to divide big messages +// in smaller chunks and send them at idle +// time. +// + +class EncodeBuffer; +class DecodeBuffer; + +class SplitStore; +class CommitStore; + +// +// Preferred message streaming policy. +// + +typedef enum +{ + split_none = -1, + split_async = 1, + split_sync + +} T_split_mode; + +// +// Current state of the split. Used to +// implement the state machine. +// + +typedef enum +{ + split_undefined = -1, + split_added, + split_missed, + split_loaded, + split_aborted, + split_notified + +} T_split_state; + +class Split +{ + friend class SplitStore; + friend class CommitStore; + + public: + + Split(); + + ~Split(); + + // + // Note that, differently from the message + // store, the split store doesn't account + // for the data offset when dealing with + // the data. This means that both the size_ + // and c_size members represent the actual + // size of the data part. + // + + void compressedSize(int size) + { + c_size_ = size; + + store_ -> validateSize(d_size_, c_size_); + } + + int compressedSize() + { + return c_size_; + } + + int plainSize() + { + return i_size_ + d_size_; + } + + T_checksum getChecksum() + { + return checksum_; + } + + MessageStore *getStore() + { + return store_; + } + + T_split_state getState() + { + return state_; + } + + T_store_action getAction() + { + return action_; + } + + // + // We may need to find the resource + // associated to the split message + // because old protocol version use + // a single store for all splits. + // + + int getResource() + { + return resource_; + } + + int getRequest() + { + return store_ -> opcode(); + } + + int getPosition() + { + return position_; + } + + T_split_mode getMode() + { + return mode_; + } + + void setPolicy(int load, int save) + { + load_ = load; + save_ = save; + } + + void setState(T_split_state state) + { + state_ = state; + } + + private: + + // + // The agent's resource which is splitting + // the message. + // + + int resource_; + + // + // Where to find the message in the message + // store or the X sequence number of the + // original request, in recent versions. + // + + int position_; + + // + // Which store is involved. + // + + MessageStore *store_; + + // + // Identity size of the message. + // + + int i_size_; + + // + // This is the uncompressed data size of the + // original message. + // + + int d_size_; + + // + // This is the size of the compressed data, + // if the data is stored in this form. + // + + int c_size_; + + // + // Size of the data buffer, as known by the + // encoding side. This field is only used at + // the decoding side. The remote size can be + // different from the actual data size, if + // the encoding side did not confirm that it + // received the abort split event. + // + + int r_size_; + + // + // Position in the data buffer that will be + // the target of the next send or receive + // operation while streaming the message. + // + + int next_; + + // + // Load or save the split to disk. + // + + int load_; + int save_; + + // + // Checksum of the original message. + // + + T_checksum checksum_; + + // + // Was this split confirmed or aborted? + // + + T_split_state state_; + + // + // What's the policy for sending this split? + // + + T_split_mode mode_; + + // + // Operation that had been performed on the + // store at the time the split was added. + // + + T_store_action action_; + + // + // Container for the identity and data part + // of the X message. + // + + T_data identity_; + T_data data_; + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +class SplitStore +{ + public: + + SplitStore(StaticCompressor *compressor, CommitStore *commits, int resource); + + ~SplitStore(); + + Split *getFirstSplit() const + { + if (splits_ -> size() > 0) + { + return (*(splits_ -> begin())); + } + + return NULL; + } + + Split *getLastSplit() const + { + if (splits_ -> size() > 0) + { + return (*(--(splits_ -> end()))); + } + + return NULL; + } + + int getNodeSize(const Split *split) const + { + // + // Take in account 64 bytes of overhead + // for each node. + // + + return (sizeof(class Split) + 64 + + split -> i_size_ + split -> d_size_); + } + + int getStorageSize() + { + return splitStorageSize_; + } + + static int getTotalSize() + { + return totalSplitSize_; + } + + static int getTotalStorageSize() + { + return totalSplitStorageSize_; + } + + int getResource() + { + return resource_; + } + + int getSize() + { + return splits_ -> size(); + } + + T_splits *getSplits() + { + return splits_; + } + + // + // Used, respectively, at the encoding + // and decoding side. + // + + Split *add(MessageStore *store, int resource, T_split_mode mode, + int position, T_store_action action, T_checksum checksum, + const unsigned char *buffer, const int size); + + Split *add(MessageStore *store, int resource, int position, + T_store_action action, T_checksum checksum, + unsigned char *buffer, const int size); + + // + // Handle the streaming of the message data. + // + + int send(EncodeBuffer &encodeBuffer, int packetSize); + + int receive(DecodeBuffer &decodeBuffer); + + // + // Remove the top element of the split store + // and update the storage size. + // + + void remove(Split *split); + + // + // Load the message from disk and replace the + // message in the store with the new copy. + // + + int load(Split *split); + + // + // Save the data to disk after the message has + // been recomposed at the local side. + // + + int save(Split *split); + + // + // Find the message on disk and update the last + // modification time. This is currently unused. + // + + int find(Split *split); + + // + // Remove the element on top of the queue and + // discard any split data that still needs to + // be transferred. + // + + Split *pop(); + + // + // Dump the content of the store. + // + + void dump(); + + protected: + + // + // Repository where to add the splits. + // + + T_splits *splits_; + + // + // Compress and decompress the data payload. + // + + StaticCompressor *compressor_; + + private: + + int start(EncodeBuffer &encodeBuffer); + + int start(DecodeBuffer &decodeBuffer); + + void push(Split *split); + + // + // Determine the name of the file object based + // on the checksum. + // + + const char *name(const T_checksum checksum); + + // + // The number of elements and data bytes + // in the repository. + // + + int splitStorageSize_; + + static int totalSplitSize_; + static int totalSplitStorageSize_; + + // + // Current element being transferred. + // + + T_splits::iterator current_; + + // + // Repository where to move the splits + // after they are completely recomposed. + // + + CommitStore *commits_; + + // + // Index in the client store or none, + // if this is a commit store. + // + + int resource_; + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +class CommitStore : public SplitStore +{ + // + // This is just a split store. + // + + public: + + CommitStore(StaticCompressor *compressor) + + : SplitStore(compressor, NULL, nothing) + { + } + + // + // Move identity and data of the split to the + // provided buffer, uncompressing the message, + // if needed. + // + + int expand(Split *split, unsigned char *buffer, const int size); + + // + // We recomposed the data part. If the message + // was originally added to the message store, + // replace the data and/or update the size. + // + + int update(Split *split); + + // + // Remove the split from the commit queue. + // + + Split *pop(); + + // + // This is just used for debug. It checks + // if any message in the message store has + // an invalid number of locks. + // + + int validate(Split *split); +}; + +#endif /* Split_H */ diff --git a/nxcomp/src/StaticCompressor.cpp b/nxcomp/src/StaticCompressor.cpp new file mode 100644 index 000000000..b47193354 --- /dev/null +++ b/nxcomp/src/StaticCompressor.cpp @@ -0,0 +1,432 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Z.h" +#include "Misc.h" +#include "Control.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +#include "StaticCompressor.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +StaticCompressor::StaticCompressor(int compressionLevel, + int compressionThreshold) +{ + buffer_ = NULL; + bufferSize_ = 0; + + compressionStream_.zalloc = (alloc_func) 0; + compressionStream_.zfree = (free_func) 0; + compressionStream_.opaque = (voidpf) 0; + + decompressionStream_.zalloc = (alloc_func) 0; + decompressionStream_.zfree = (free_func) 0; + decompressionStream_.opaque = (void *) 0; + + decompressionStream_.next_in = (Bytef *) 0; + decompressionStream_.avail_in = 0; + + #ifdef TEST + *logofs << "StaticCompressor: Compression level is " + << compressionLevel << ".\n" << logofs_flush; + #endif + + int result = deflateInit2(&compressionStream_, compressionLevel, Z_DEFLATED, + 15, 9, Z_DEFAULT_STRATEGY); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Cannot initialize the " + << "compression stream. Error is '" << zError(result) + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot initialize the compression " + << "stream. Error is '" << zError(result) << "'.\n"; + + HandleAbort(); + } + + result = inflateInit2(&decompressionStream_, 15); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Cannot initialize the " + << "decompression stream. Error is '" << zError(result) + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot initialize the decompression " + << "stream. Error is '" << zError(result) << "'.\n"; + + HandleAbort(); + } + + #ifdef TEST + *logofs << "StaticCompressor: Compression threshold is " + << compressionThreshold << ".\n" << logofs_flush; + #endif + + threshold_ = compressionThreshold; +} + +StaticCompressor::~StaticCompressor() +{ + int result = deflateEnd(&compressionStream_); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Cannot deinitialize the " + << "compression stream. Error is '" << zError(result) + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot deinitialize the compression " + << "stream. Error is '" << zError(result) << "'.\n"; + } + + result = inflateEnd(&decompressionStream_); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Cannot deinitialize the " + << "decompression stream. Error is '" << zError(result) + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot deinitialize the decompression " + << "stream. Error is '" << zError(result) << "'.\n"; + } + + delete [] buffer_; +} + +// +// This function compresses and encodes the compressed +// buffer. It returns a pointer to the internal buffer +// where data was compressed. +// + +int StaticCompressor::compressBuffer(const unsigned char *plainBuffer, + const unsigned int plainSize, + unsigned char *&compressedBuffer, + unsigned int &compressedSize, + EncodeBuffer &encodeBuffer) +{ + if (control -> LocalDataCompression == 0 || + compressBuffer(plainBuffer, plainSize, + compressedBuffer, compressedSize) <= 0) + { + encodeBuffer.encodeBoolValue(0); + + encodeBuffer.encodeMemory(plainBuffer, plainSize); + + return 0; + } + else + { + encodeBuffer.encodeBoolValue(1); + + encodeBuffer.encodeValue(compressedSize, 32, 14); + encodeBuffer.encodeValue(plainSize, 32, 14); + + encodeBuffer.encodeMemory(compressedBuffer, compressedSize); + + return 1; + } +} + +// +// This function compresses data into a dynamically +// allocated buffer and returns a pointer to it, so +// application must copy data before the next call. +// + +int StaticCompressor::compressBuffer(const unsigned char *plainBuffer, + const unsigned int plainSize, + unsigned char *&compressedBuffer, + unsigned int &compressedSize) +{ + #ifdef DEBUG + *logofs << "StaticCompressor: Called for buffer at " + << (void *) plainBuffer << ".\n" + << logofs_flush; + #endif + + compressedSize = plainSize; + + if (plainSize < (unsigned int) threshold_) + { + #ifdef TEST + *logofs << "StaticCompressor: Leaving buffer unchanged. " + << "Plain size is " << plainSize << " with threshold " + << (unsigned int) threshold_ << ".\n" << logofs_flush; + #endif + + return 0; + } + + // + // Determine the size of the temporary + // buffer. + // + + unsigned int newSize = plainSize + (plainSize / 1000) + 12; + + // + // Allocate a new buffer if it grows + // beyond 64K. + // + + if (buffer_ == NULL || (bufferSize_ > 65536 && + newSize < bufferSize_ / 2) || newSize > bufferSize_) + { + delete [] buffer_; + + buffer_ = new unsigned char[newSize]; + + if (buffer_ == NULL) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Can't allocate compression " + << "buffer of " << newSize << " bytes. Error is " << EGET() + << " ' " << ESTR() << "'.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Can't allocate compression buffer of " + << newSize << " bytes. Error is " << EGET() + << " '" << ESTR() << "'.\n"; + + bufferSize_ = 0; + + return 0; + } + + bufferSize_ = newSize; + } + + unsigned int resultingSize = newSize; + + int result = ZCompress(&compressionStream_, buffer_, &resultingSize, + plainBuffer, plainSize); + + if (result == Z_OK) + { + if (resultingSize > newSize) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Overflow in compression " + << "buffer size. " << "Expected size was " << newSize + << " while it is " << resultingSize << ".\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Overflow in compress buffer size. " + << "Expected size was " << newSize << " while it is " + << resultingSize << ".\n"; + + return -1; + } + else if (resultingSize >= plainSize) + { + #ifdef TEST + *logofs << "StaticCompressor: Leaving buffer unchanged. " + << "Plain size is " << plainSize << " compressed " + << "size is " << resultingSize << ".\n" + << logofs_flush; + #endif + + return 0; + } + + compressedBuffer = buffer_; + compressedSize = resultingSize; + + #ifdef TEST + *logofs << "StaticCompressor: Compressed buffer from " + << plainSize << " to " << resultingSize + << " bytes.\n" << logofs_flush; + #endif + + return 1; + } + + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Failed compression of buffer. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failed compression of buffer. " + << "Error is '" << zError(result) << "'.\n"; + + return -1; +} + +int StaticCompressor::decompressBuffer(unsigned char *plainBuffer, + unsigned int plainSize, + const unsigned char *&compressedBuffer, + unsigned int &compressedSize, + DecodeBuffer &decodeBuffer) +{ + #ifdef DEBUG + *logofs << "StaticCompressor: Called for buffer at " + << (void *) plainBuffer << ".\n" + << logofs_flush; + #endif + + unsigned int value; + + decodeBuffer.decodeBoolValue(value); + + if (value == 0) + { + memcpy(plainBuffer, + decodeBuffer.decodeMemory(plainSize), + plainSize); + + return 0; + } + + unsigned int checkSize = plainSize; + + decodeBuffer.decodeValue(value, 32, 14); + compressedSize = value; + + decodeBuffer.decodeValue(value, 32, 14); + checkSize = value; + + // + // If caller needs the original compressed + // data it must copy this to its own buffer + // before using any further decode function. + // + + compressedBuffer = decodeBuffer.decodeMemory(compressedSize); + + int result = ZDecompress(&decompressionStream_, plainBuffer, &checkSize, + compressedBuffer, compressedSize); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Failure decompressing buffer. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Failure decompressing buffer. " + << "Error is '" << zError(result) << "'.\n"; + + return -1; + } + else if (plainSize != checkSize) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Expected decompressed size was " + << plainSize << " while it is " << checkSize + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Expected decompressed size was " + << plainSize << " while it is " << checkSize + << ".\n"; + + return -1; + } + + return 1; +} + +// +// This is used to uncompress on-the-fly +// messages whose data has been stored +// in compressed format. +// + +int StaticCompressor::decompressBuffer(unsigned char *plainBuffer, + const unsigned int plainSize, + const unsigned char *compressedBuffer, + const unsigned int compressedSize) +{ + #ifdef TEST + *logofs << "StaticCompressor: Called for buffer at " + << (void *) plainBuffer << ".\n" + << logofs_flush; + #endif + + unsigned int checkSize = plainSize; + + int result = ZDecompress(&decompressionStream_, plainBuffer, &checkSize, + compressedBuffer, compressedSize); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Failure decompressing buffer. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + return -1; + } + + if (plainSize != checkSize) + { + #ifdef PANIC + *logofs << "StaticCompressor: PANIC! Expected decompressed size was " + << plainSize << " while it is " << checkSize + << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Expected decompressed size was " + << plainSize << " while it is " << checkSize + << ".\n"; + + return -1; + } + + #ifdef TEST + *logofs << "StaticCompressor: Decompressed buffer from " + << compressedSize << " to " << plainSize + << " bytes.\n" << logofs_flush; + #endif + + return 1; +} diff --git a/nxcomp/src/StaticCompressor.h b/nxcomp/src/StaticCompressor.h new file mode 100644 index 000000000..e0b81a527 --- /dev/null +++ b/nxcomp/src/StaticCompressor.h @@ -0,0 +1,80 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef StaticCompressor_H +#define StaticCompressor_H + +#include "Z.h" + +class EncodeBuffer; +class DecodeBuffer; + +class StaticCompressor +{ + public: + + StaticCompressor(int compressionLevel, int compressionThreshold); + + ~StaticCompressor(); + + int compressBuffer(const unsigned char *plainBuffer, const unsigned int plainSize, + unsigned char *&compressedBuffer, unsigned int &compressedSize, + EncodeBuffer &encodeBuffer); + + int compressBuffer(const unsigned char *plainBuffer, const unsigned int plainSize, + unsigned char *&compressedBuffer, unsigned int &compressedSize); + + int decompressBuffer(unsigned char *plainBuffer, unsigned int plainSize, + const unsigned char *&compressedBuffer, unsigned int &compressedSize, + DecodeBuffer &decodeBuffer); + + int decompressBuffer(unsigned char *plainBuffer, const unsigned int plainSize, + const unsigned char *compressedBuffer, const unsigned compressedSize); + + static int isCompressionLevel(int compressionLevel) + { + return (compressionLevel == Z_DEFAULT_COMPRESSION || + (compressionLevel >= Z_NO_COMPRESSION && + compressionLevel <= Z_BEST_COMPRESSION)); + } + + int fullReset() + { + return (deflateReset(&compressionStream_) == Z_OK && + inflateReset(&decompressionStream_) == Z_OK); + } + + private: + + z_stream compressionStream_; + z_stream decompressionStream_; + + unsigned char *buffer_; + unsigned int bufferSize_; + + int threshold_; +}; + +#endif diff --git a/nxcomp/src/Statistics.cpp b/nxcomp/src/Statistics.cpp new file mode 100644 index 000000000..ab8fd74dc --- /dev/null +++ b/nxcomp/src/Statistics.cpp @@ -0,0 +1,2007 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "Statistics.h" + +#include "Control.h" + +#include "Proxy.h" + +#include "ClientStore.h" +#include "ServerStore.h" + +// +// Length of temporary buffer +// used to format output. +// + +#define FORMAT_LENGTH 1024 + +// +// Log level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Note that when presenting statistics we invert the +// correct semantics of X client and server entities. +// This is questionable, but matches the user's pers- +// pective of running remote X applications on its +// local client. +// + +Statistics::Statistics(Proxy *proxy) : proxy_(proxy) +{ + transportPartial_.idleTime_ = 0; + transportPartial_.readTime_ = 0; + transportPartial_.writeTime_ = 0; + transportPartial_.proxyBytesIn_ = 0; + transportPartial_.proxyBytesOut_ = 0; + transportPartial_.proxyFramesIn_ = 0; + transportPartial_.proxyFramesOut_ = 0; + transportPartial_.proxyWritesOut_ = 0; + transportPartial_.compressedBytesIn_ = 0; + transportPartial_.compressedBytesOut_ = 0; + transportPartial_.decompressedBytesIn_ = 0; + transportPartial_.decompressedBytesOut_ = 0; + transportPartial_.framingBitsOut_ = 0; + + transportTotal_.idleTime_ = 0; + transportTotal_.readTime_ = 0; + transportTotal_.writeTime_ = 0; + transportTotal_.proxyBytesIn_ = 0; + transportTotal_.proxyBytesOut_ = 0; + transportTotal_.proxyFramesIn_ = 0; + transportTotal_.proxyFramesOut_ = 0; + transportTotal_.proxyWritesOut_ = 0; + transportTotal_.compressedBytesIn_ = 0; + transportTotal_.compressedBytesOut_ = 0; + transportTotal_.decompressedBytesIn_ = 0; + transportTotal_.decompressedBytesOut_ = 0; + transportTotal_.framingBitsOut_ = 0; + + for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) + { + protocolPartial_.requestCached_[i] = 0; + protocolPartial_.requestReplied_[i] = 0; + protocolPartial_.requestCount_[i] = 0; + protocolPartial_.requestBitsIn_[i] = 0; + protocolPartial_.requestBitsOut_[i] = 0; + + protocolPartial_.renderRequestCached_[i] = 0; + protocolPartial_.renderRequestCount_[i] = 0; + protocolPartial_.renderRequestBitsIn_[i] = 0; + protocolPartial_.renderRequestBitsOut_[i] = 0; + + protocolPartial_.replyCached_[i] = 0; + protocolPartial_.replyCount_[i] = 0; + protocolPartial_.replyBitsIn_[i] = 0; + protocolPartial_.replyBitsOut_[i] = 0; + + protocolPartial_.eventCached_[i] = 0; + protocolPartial_.eventCount_[i] = 0; + protocolPartial_.eventBitsIn_[i] = 0; + protocolPartial_.eventBitsOut_[i] = 0; + + protocolTotal_.requestCached_[i] = 0; + protocolTotal_.requestReplied_[i] = 0; + protocolTotal_.requestCount_[i] = 0; + protocolTotal_.requestBitsIn_[i] = 0; + protocolTotal_.requestBitsOut_[i] = 0; + + protocolTotal_.renderRequestCached_[i] = 0; + protocolTotal_.renderRequestCount_[i] = 0; + protocolTotal_.renderRequestBitsIn_[i] = 0; + protocolTotal_.renderRequestBitsOut_[i] = 0; + + protocolTotal_.replyCached_[i] = 0; + protocolTotal_.replyCount_[i] = 0; + protocolTotal_.replyBitsIn_[i] = 0; + protocolTotal_.replyBitsOut_[i] = 0; + + protocolTotal_.eventCached_[i] = 0; + protocolTotal_.eventCount_[i] = 0; + protocolTotal_.eventBitsIn_[i] = 0; + protocolTotal_.eventBitsOut_[i] = 0; + } + + protocolPartial_.cupsCount_ = 0; + protocolPartial_.cupsBitsIn_ = 0; + protocolPartial_.cupsBitsOut_ = 0; + + protocolPartial_.smbCount_ = 0; + protocolPartial_.smbBitsIn_ = 0; + protocolPartial_.smbBitsOut_ = 0; + + protocolPartial_.mediaCount_ = 0; + protocolPartial_.mediaBitsIn_ = 0; + protocolPartial_.mediaBitsOut_ = 0; + + protocolPartial_.httpCount_ = 0; + protocolPartial_.httpBitsIn_ = 0; + protocolPartial_.httpBitsOut_ = 0; + + protocolPartial_.fontCount_ = 0; + protocolPartial_.fontBitsIn_ = 0; + protocolPartial_.fontBitsOut_ = 0; + + protocolPartial_.slaveCount_ = 0; + protocolPartial_.slaveBitsIn_ = 0; + protocolPartial_.slaveBitsOut_ = 0; + + protocolTotal_.cupsCount_ = 0; + protocolTotal_.cupsBitsIn_ = 0; + protocolTotal_.cupsBitsOut_ = 0; + + protocolTotal_.smbCount_ = 0; + protocolTotal_.smbBitsIn_ = 0; + protocolTotal_.smbBitsOut_ = 0; + + protocolTotal_.mediaCount_ = 0; + protocolTotal_.mediaBitsIn_ = 0; + protocolTotal_.mediaBitsOut_ = 0; + + protocolTotal_.httpCount_ = 0; + protocolTotal_.httpBitsIn_ = 0; + protocolTotal_.httpBitsOut_ = 0; + + protocolTotal_.fontCount_ = 0; + protocolTotal_.fontBitsIn_ = 0; + protocolTotal_.fontBitsOut_ = 0; + + protocolTotal_.slaveCount_ = 0; + protocolTotal_.slaveBitsIn_ = 0; + protocolTotal_.slaveBitsOut_ = 0; + + packedPartial_.packedBytesIn_ = 0; + packedPartial_.packedBytesOut_ = 0; + + packedTotal_.packedBytesIn_ = 0; + packedTotal_.packedBytesOut_ = 0; + + splitPartial_.splitCount_ = 0; + splitPartial_.splitAborted_ = 0; + splitPartial_.splitAbortedBytesOut_ = 0; + + splitTotal_.splitCount_ = 0; + splitTotal_.splitAborted_ = 0; + splitTotal_.splitAbortedBytesOut_ = 0; + + overallPartial_.overallBytesIn_ = 0; + overallPartial_.overallBytesOut_ = 0; + + overallTotal_.overallBytesIn_ = 0; + overallTotal_.overallBytesOut_ = 0; + + proxyData_.protocolCount_ = 0; + proxyData_.controlCount_ = 0; + proxyData_.splitCount_ = 0; + proxyData_.dataCount_ = 0; + + proxyData_.streamRatio_ = 1; + + startShortFrameTs_ = getTimestamp(); + startLongFrameTs_ = getTimestamp(); + startFrameTs_ = getTimestamp(); + + bytesInShortFrame_ = 0; + bytesInLongFrame_ = 0; + + bitrateInShortFrame_ = 0; + bitrateInLongFrame_ = 0; + + topBitrate_ = 0; + + congestionInFrame_ = 0; +} + +Statistics::~Statistics() +{ +} + +int Statistics::resetPartialStats() +{ + transportPartial_.idleTime_ = 0; + transportPartial_.readTime_ = 0; + transportPartial_.writeTime_ = 0; + transportPartial_.proxyBytesIn_ = 0; + transportPartial_.proxyBytesOut_ = 0; + transportPartial_.proxyFramesIn_ = 0; + transportPartial_.proxyFramesOut_ = 0; + transportPartial_.proxyWritesOut_ = 0; + transportPartial_.compressedBytesIn_ = 0; + transportPartial_.compressedBytesOut_ = 0; + transportPartial_.decompressedBytesIn_ = 0; + transportPartial_.decompressedBytesOut_ = 0; + transportPartial_.framingBitsOut_ = 0; + + for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) + { + protocolPartial_.requestCached_[i] = 0; + protocolPartial_.requestReplied_[i] = 0; + protocolPartial_.requestCount_[i] = 0; + protocolPartial_.requestBitsIn_[i] = 0; + protocolPartial_.requestBitsOut_[i] = 0; + + protocolPartial_.renderRequestCached_[i] = 0; + protocolPartial_.renderRequestCount_[i] = 0; + protocolPartial_.renderRequestBitsIn_[i] = 0; + protocolPartial_.renderRequestBitsOut_[i] = 0; + + protocolPartial_.replyCached_[i] = 0; + protocolPartial_.replyCount_[i] = 0; + protocolPartial_.replyBitsIn_[i] = 0; + protocolPartial_.replyBitsOut_[i] = 0; + + protocolPartial_.eventCached_[i] = 0; + protocolPartial_.eventCount_[i] = 0; + protocolPartial_.eventBitsIn_[i] = 0; + protocolPartial_.eventBitsOut_[i] = 0; + } + + protocolPartial_.cupsCount_ = 0; + protocolPartial_.cupsBitsIn_ = 0; + protocolPartial_.cupsBitsOut_ = 0; + + protocolPartial_.smbCount_ = 0; + protocolPartial_.smbBitsIn_ = 0; + protocolPartial_.smbBitsOut_ = 0; + + protocolPartial_.mediaCount_ = 0; + protocolPartial_.mediaBitsIn_ = 0; + protocolPartial_.mediaBitsOut_ = 0; + + protocolPartial_.httpCount_ = 0; + protocolPartial_.httpBitsIn_ = 0; + protocolPartial_.httpBitsOut_ = 0; + + protocolPartial_.fontCount_ = 0; + protocolPartial_.fontBitsIn_ = 0; + protocolPartial_.fontBitsOut_ = 0; + + protocolPartial_.slaveCount_ = 0; + protocolPartial_.slaveBitsIn_ = 0; + protocolPartial_.slaveBitsOut_ = 0; + + packedPartial_.packedBytesIn_ = 0; + packedPartial_.packedBytesOut_ = 0; + + splitPartial_.splitCount_ = 0; + splitPartial_.splitAborted_ = 0; + splitPartial_.splitAbortedBytesOut_ = 0; + + overallPartial_.overallBytesIn_ = 0; + overallPartial_.overallBytesOut_ = 0; + + return 1; +} + +void Statistics::addCompressedBytes(unsigned int bytesIn, unsigned int bytesOut) +{ + transportPartial_.compressedBytesIn_ += bytesIn; + transportTotal_.compressedBytesIn_ += bytesIn; + + transportPartial_.compressedBytesOut_ += bytesOut; + transportTotal_.compressedBytesOut_ += bytesOut; + + double ratio = bytesIn / bytesOut; + + if (ratio < 1) + { + ratio = 1; + } + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! Old ratio was " + << proxyData_.streamRatio_ << " current is " + << (double) ratio << " new ratio is " << (double) + ((proxyData_.streamRatio_ * 2) + ratio) / 3 << ".\n" + << logofs_flush; + #endif + + proxyData_.streamRatio_ = ((proxyData_.streamRatio_ * 2) + ratio) / 3; + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! Updated compressed bytes " + << "with " << bytesIn << " in " << bytesOut << " out " + << "and ratio " << (double) proxyData_.streamRatio_ + << ".\n" << logofs_flush; + #endif +} + +// +// Recalculate the current bitrate. The bytes written +// are accounted at the time the transport actually +// writes the data to the network, not at the time it +// receives the data from the upper layers. The reason +// is that data can be compressed by the stream com- +// pressor, so we can become aware of the new bitrate +// only afer having flushed the ZLIB stream. This also +// means that, to have a reliable estimate, we need to +// flush the link often. +// + +void Statistics::updateBitrate(int bytes) +{ + T_timestamp thisFrameTs = getNewTimestamp(); + + int diffFramesInMs = diffTimestamp(startFrameTs_, thisFrameTs); + + #ifdef DEBUG + *logofs << "Statistics: Difference since previous timestamp is " + << diffFramesInMs << " Ms.\n" << logofs_flush; + #endif + + if (diffFramesInMs > 0) + { + #ifdef DEBUG + *logofs << "Statistics: Removing " << diffFramesInMs + << " Ms in short and long time frame.\n" + << logofs_flush; + #endif + + int shortBytesToRemove = (int) (((double) bytesInShortFrame_ * (double) diffFramesInMs) / + (double) control -> ShortBitrateTimeFrame); + + int longBytesToRemove = (int) (((double) bytesInLongFrame_ * (double) diffFramesInMs) / + (double) control -> LongBitrateTimeFrame); + + #ifdef DEBUG + *logofs << "Statistics: Removing " << shortBytesToRemove + << " bytes from " << bytesInShortFrame_ + << " in the short frame.\n" << logofs_flush; + #endif + + bytesInShortFrame_ -= shortBytesToRemove; + + if (bytesInShortFrame_ < 0) + { + #ifdef TEST + *logofs << "Statistics: Bytes in short frame are " + << bytesInShortFrame_ << ". Set to 0.\n" + << logofs_flush; + #endif + + bytesInShortFrame_ = 0; + } + + #ifdef DEBUG + *logofs << "Statistics: Removing " << longBytesToRemove + << " bytes from " << bytesInLongFrame_ + << " in the long frame.\n" << logofs_flush; + #endif + + bytesInLongFrame_ -= longBytesToRemove; + + if (bytesInLongFrame_ < 0) + { + #ifdef TEST + *logofs << "Statistics: Bytes in long frame are " + << bytesInLongFrame_ << ". Set to 0.\n" + << logofs_flush; + #endif + + bytesInLongFrame_ = 0; + } + + int diffStartInMs; + + diffStartInMs = diffTimestamp(thisFrameTs, startShortFrameTs_); + + if (diffStartInMs > control -> ShortBitrateTimeFrame) + { + addMsTimestamp(startShortFrameTs_, diffStartInMs); + } + + diffStartInMs = diffTimestamp(thisFrameTs, startLongFrameTs_); + + if (diffStartInMs > control -> LongBitrateTimeFrame) + { + addMsTimestamp(startLongFrameTs_, diffStartInMs); + } + + startFrameTs_ = thisFrameTs; + } + + #ifdef DEBUG + *logofs << "Statistics: Adding " << bytes << " bytes to " + << bytesInShortFrame_ << " in the short frame.\n" + << logofs_flush; + #endif + + bytesInShortFrame_ = bytesInShortFrame_ + bytes; + + #ifdef DEBUG + *logofs << "Statistics: Adding " << bytes << " bytes to " + << bytesInLongFrame_ << " in the long frame.\n" + << logofs_flush; + #endif + + bytesInLongFrame_ = bytesInLongFrame_ + bytes; + + bitrateInShortFrame_ = (int) ((double) bytesInShortFrame_ / + ((double) control -> ShortBitrateTimeFrame / 1000)); + + bitrateInLongFrame_ = (int) ((double) bytesInLongFrame_ / + ((double) control -> LongBitrateTimeFrame / 1000)); + + if (bitrateInShortFrame_ > topBitrate_) + { + topBitrate_ = bitrateInShortFrame_; + } + + #ifdef TEST + *logofs << "Statistics: Current bitrate is short " << bitrateInShortFrame_ + << " long " << bitrateInLongFrame_ << " top " << topBitrate_ + << ".\n" << logofs_flush; + #endif +} + +void Statistics::updateCongestion(int remaining, int limit) +{ + #ifdef TEST + *logofs << "Statistics: Updating the congestion " + << "counters at " << strMsTimestamp() + << ".\n" << logofs_flush; + #endif + + double current = remaining; + + if (current < 0) + { + current = 0; + } + + current = 9 * (limit - current) / limit; + + #ifdef TEST + *logofs << "Statistics: Current congestion is " + << current << " with " << limit << " tokens " + << "and " << remaining << " remaining.\n" + << logofs_flush; + #endif + + // + // If the current congestion counter is greater + // than the previous, take the current value, + // otherwise ramp down the value by calculating + // the average of the last 8 updates. + // + + #ifdef TEST + *logofs << "Statistics: Old congestion was " + << congestionInFrame_; + #endif + + if (current >= congestionInFrame_) + { + congestionInFrame_ = current; + } + else + { + congestionInFrame_ = ((congestionInFrame_ * 7) + current) / 8; + } + + #ifdef TEST + *logofs << " new congestion is " + << ((congestionInFrame_ * 7) + current) / 8 + << ".\n" << logofs_flush; + #endif + + // + // Call the function with 0 bytes flushed + // so the agent can update its congestion + // counter. + // + + FlushCallback(0); +} + +int Statistics::getClientCacheStats(int type, char *&buffer) +{ + if (type != PARTIAL_STATS && type != TOTAL_STATS) + { + #ifdef PANIC + *logofs << "Statistics: PANIC! Cannot produce statistics " + << "with qualifier '" << type << "'.\n" + << logofs_flush; + #endif + + return -1; + } + + // + // Print message cache data according + // to local and remote view. + // + + MessageStore *currentStore = NULL; + MessageStore *anyStore = NULL; + + char format[FORMAT_LENGTH]; + + strcat(buffer, "\nNX Cache Statistics\n"); + strcat(buffer, "-------------------\n\n"); + + for (int m = proxy_client; m <= proxy_server; m++) + { + if (m == proxy_client) + { + strcat(buffer, "Request\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n"); + strcat(buffer, "-------\t------\t--------------\t\t--------------\t\t-----------\n"); + } + else + { + strcat(buffer, "\nReply\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n"); + strcat(buffer, "-----\t------\t--------------\t\t--------------\t\t-----------\n"); + } + + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + if (m == proxy_client) + { + currentStore = proxy_ -> getClientStore() -> getRequestStore(i); + } + else + { + currentStore = proxy_ -> getServerStore() -> getReplyStore(i); + } + + if (currentStore != NULL && + (currentStore -> getLocalStorageSize() || + currentStore -> getRemoteStorageSize())) + { + anyStore = currentStore; + + sprintf(format, "#%d\t%d\t", i, currentStore -> getSize()); + + strcat(buffer, format); + + sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getLocalStorageSize(), + ((double) currentStore -> getLocalStorageSize()) / 1024); + + strcat(buffer, format); + + sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getRemoteStorageSize(), + ((double) currentStore -> getRemoteStorageSize()) / 1024); + + strcat(buffer, format); + + sprintf(format, "%d/%.0f KB\n", currentStore -> cacheSlots, + ((double) control -> getUpperStorageSize() / 100 * + currentStore -> cacheThreshold) / 1024); + + strcat(buffer, format); + } + } + + if (anyStore == NULL) + { + strcat(buffer, "N/A\n"); + } + } + + if (anyStore != NULL) + { + sprintf(format, "\ncache: %d bytes (%d KB) available at server.\n", + control -> ClientTotalStorageSize, + control -> ClientTotalStorageSize / 1024); + + strcat(buffer, format); + + sprintf(format, " %d bytes (%d KB) available at client.\n\n", + control -> ServerTotalStorageSize, + control -> ServerTotalStorageSize / 1024); + + strcat(buffer, format); + + sprintf(format, " %d bytes (%d KB) allocated at server.\n", + anyStore -> getLocalTotalStorageSize(), + anyStore -> getLocalTotalStorageSize() / 1024); + + strcat(buffer, format); + + sprintf(format, " %d bytes (%d KB) allocated at client.\n\n\n", + anyStore -> getRemoteTotalStorageSize(), + anyStore -> getRemoteTotalStorageSize() / 1024); + + strcat(buffer, format); + } + else + { + strcat(buffer, "\ncache: N/A\n\n"); + } + + return 1; +} + +int Statistics::getClientProtocolStats(int type, char *&buffer) +{ + if (type != PARTIAL_STATS && type != TOTAL_STATS) + { + #ifdef PANIC + *logofs << "Statistics: PANIC! Cannot produce statistics " + << "with qualifier '" << type << "'.\n" + << logofs_flush; + #endif + + return -1; + } + + struct T_transportData *transportData; + struct T_protocolData *protocolData; + struct T_overallData *overallData; + + if (type == PARTIAL_STATS) + { + transportData = &transportPartial_; + protocolData = &protocolPartial_; + overallData = &overallPartial_; + } + else + { + transportData = &transportTotal_; + protocolData = &protocolTotal_; + overallData = &overallTotal_; + } + + char format[FORMAT_LENGTH]; + + double countRequestIn = 0; + double countCachedRequestIn = 0; + double countRepliedRequestIn = 0; + + double countRequestBitsIn = 0; + double countRequestBitsOut = 0; + + double countAnyIn = 0; + double countBitsIn = 0; + double countBitsOut = 0; + + // + // Print request data. + // + + strcat(buffer, "NX Server Side Protocol Statistics\n"); + strcat(buffer, "----------------------------------\n\n"); + + // + // Print render data. + // + + strcat(buffer, "Render Total\tCached\tBits In\t\tBits Out\tBits/Request\t\tRatio\n"); + strcat(buffer, "------- -----\t------\t-------\t\t--------\t------------\t\t-----\n"); + + for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) + { + if (protocolData -> renderRequestCount_[i]) + { + sprintf(format, "#%d ", i); + + while (strlen(format) < 8) + { + strcat(format, " "); + } + + strcat(buffer, format); + + if (protocolData -> renderRequestCached_[i] > 0) + { + sprintf(format, "%.0f\t%.0f", protocolData -> renderRequestCount_[i], + protocolData -> renderRequestCached_[i]); + } + else + { + sprintf(format, "%.0f\t", protocolData -> renderRequestCount_[i]); + } + + strcat(buffer, format); + + sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", + protocolData -> renderRequestBitsIn_[i], protocolData -> renderRequestBitsIn_[i] / 8192, + protocolData -> renderRequestBitsOut_[i], protocolData -> renderRequestBitsOut_[i] / 8192, + protocolData -> renderRequestBitsIn_[i] / protocolData -> renderRequestCount_[i], + protocolData -> renderRequestBitsOut_[i] / protocolData -> renderRequestCount_[i]); + + strcat(buffer, format); + + if (protocolData -> renderRequestBitsOut_[i] > 0) + { + sprintf(format, "%5.3f:1\n", protocolData -> renderRequestBitsIn_[i] / + protocolData -> renderRequestBitsOut_[i]); + + strcat(buffer, format); + } + else + { + strcat(buffer, "1:1\n"); + } + } + + countRequestIn += protocolData -> renderRequestCount_[i]; + countCachedRequestIn += protocolData -> renderRequestCached_[i]; + + countRequestBitsIn += protocolData -> renderRequestBitsIn_[i]; + countRequestBitsOut += protocolData -> renderRequestBitsOut_[i]; + + countAnyIn += protocolData -> renderRequestCount_[i]; + countBitsIn += protocolData -> renderRequestBitsIn_[i]; + countBitsOut += protocolData -> renderRequestBitsOut_[i]; + } + + if (countRequestIn > 0) + { + if (countCachedRequestIn > 0) + { + sprintf(format, "\ntotal: %.0f\t%.0f", countRequestIn, countCachedRequestIn); + } + else + { + sprintf(format, "\ntotal: %.0f\t", countRequestIn); + } + + strcat(buffer, format); + + sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", + countRequestBitsIn, countRequestBitsIn / 8192, countRequestBitsOut, + countRequestBitsOut / 8192, countRequestBitsIn / countRequestIn, + countRequestBitsOut / countRequestIn); + + strcat(buffer, format); + + if (countRequestBitsOut > 0) + { + sprintf(format, "%5.3f:1\n", countRequestBitsIn / countRequestBitsOut); + } + else + { + sprintf(format, "1:1\n"); + } + + strcat(buffer, format); + } + else + { + strcat(buffer, "N/A\n\n"); + } + + countRequestIn = 0; + countCachedRequestIn = 0; + + countRequestBitsIn = 0; + countRequestBitsOut = 0; + + countAnyIn = 0; + countBitsIn = 0; + countBitsOut = 0; + + // + // Print other requests' data. + // + + strcat(buffer, "\nRequest Total\tCached\tBits In\t\tBits Out\tBits/Request\t\tRatio\n"); + strcat(buffer, "------- -----\t------\t-------\t\t--------\t------------\t\t-----\n"); + + for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) + { + if (protocolData -> requestCount_[i]) + { + sprintf(format, "#%d ", i); + + while (strlen(format) < 5) + { + strcat(format, " "); + } + + // + // Mark NX agent-related requests, those + // having a reply and finally those that + // have been probably tainted by client + // side. + // + + if (i >= X_NXFirstOpcode && i <= X_NXLastOpcode) + { + strcat(format, "A"); + } + + if (i != X_NXInternalGenericReply && protocolData -> requestReplied_[i] > 0) + { + strcat(format, "R"); + } + + if (i == X_NoOperation && control -> TaintReplies) + { + strcat(format, "T"); + } + + while (strlen(format) < 8) + { + strcat(format, " "); + } + + strcat(buffer, format); + + if (protocolData -> requestCached_[i] > 0) + { + sprintf(format, "%.0f\t%.0f", protocolData -> requestCount_[i], + protocolData -> requestCached_[i]); + } + else + { + sprintf(format, "%.0f\t", protocolData -> requestCount_[i]); + } + + strcat(buffer, format); + + sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", + protocolData -> requestBitsIn_[i], protocolData -> requestBitsIn_[i] / 8192, + protocolData -> requestBitsOut_[i], protocolData -> requestBitsOut_[i] / 8192, + protocolData -> requestBitsIn_[i] / protocolData -> requestCount_[i], + protocolData -> requestBitsOut_[i] / protocolData -> requestCount_[i]); + + strcat(buffer, format); + + if (protocolData -> requestBitsOut_[i] > 0) + { + sprintf(format, "%5.3f:1\n", protocolData -> requestBitsIn_[i] / + protocolData -> requestBitsOut_[i]); + + strcat(buffer, format); + } + else + { + strcat(buffer, "1:1\n"); + } + } + + countRequestIn += protocolData -> requestCount_[i]; + countCachedRequestIn += protocolData -> requestCached_[i]; + countRepliedRequestIn += protocolData -> requestReplied_[i]; + + countRequestBitsIn += protocolData -> requestBitsIn_[i]; + countRequestBitsOut += protocolData -> requestBitsOut_[i]; + + countAnyIn += protocolData -> requestCount_[i]; + countBitsIn += protocolData -> requestBitsIn_[i]; + countBitsOut += protocolData -> requestBitsOut_[i]; + } + + if (countRequestIn > 0) + { + if (countCachedRequestIn > 0) + { + sprintf(format, "\ntotal: %.0f\t%.0f", countRequestIn, countCachedRequestIn); + } + else + { + sprintf(format, "\ntotal: %.0f\t", countRequestIn); + } + + strcat(buffer, format); + + sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", + countRequestBitsIn, countRequestBitsIn / 8192, countRequestBitsOut, + countRequestBitsOut / 8192, countRequestBitsIn / countRequestIn, + countRequestBitsOut / countRequestIn); + + strcat(buffer, format); + + if (countRequestBitsOut > 0) + { + sprintf(format, "%5.3f:1\n", countRequestBitsIn / countRequestBitsOut); + } + else + { + sprintf(format, "1:1\n"); + } + + strcat(buffer, format); + } + else + { + strcat(buffer, "N/A\n\n"); + } + + // + // Print transport data. + // + + getTimeStats(type, buffer); + + countAnyIn += protocolData -> cupsCount_; + countBitsIn += protocolData -> cupsBitsIn_; + countBitsOut += protocolData -> cupsBitsOut_; + + countAnyIn += protocolData -> smbCount_; + countBitsIn += protocolData -> smbBitsIn_; + countBitsOut += protocolData -> smbBitsOut_; + + countAnyIn += protocolData -> mediaCount_; + countBitsIn += protocolData -> mediaBitsIn_; + countBitsOut += protocolData -> mediaBitsOut_; + + countAnyIn += protocolData -> httpCount_; + countBitsIn += protocolData -> httpBitsIn_; + countBitsOut += protocolData -> httpBitsOut_; + + countAnyIn += protocolData -> fontCount_; + countBitsIn += protocolData -> fontBitsIn_; + countBitsOut += protocolData -> fontBitsOut_; + + countAnyIn += protocolData -> slaveCount_; + countBitsIn += protocolData -> slaveBitsIn_; + countBitsOut += protocolData -> slaveBitsOut_; + + // + // Save the overall amount of bytes + // coming from X clients. + // + + overallData -> overallBytesIn_ = countBitsIn / 8; + + // + // Print performance data. + // + + if (transportData -> readTime_ > 0) + { + sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n", + countAnyIn / (transportData -> readTime_ / 1000), + (countBitsIn + transportData -> framingBitsOut_) / 8192 / + (transportData -> readTime_ / 1000)); + } + else + { + sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n", + countAnyIn, (countBitsIn + transportData -> + framingBitsOut_) / 8192); + } + + strcat(buffer, format); + + strcat(buffer, "link: "); + + // + // ZLIB compression stats. + // + + getStreamStats(type, buffer); + + // + // Save the overall amount of bytes + // sent on NX proxy link. + // + + if (transportData -> compressedBytesOut_ > 0) + { + overallData -> overallBytesOut_ = transportData -> compressedBytesOut_; + } + else + { + overallData -> overallBytesOut_ = countBitsOut / 8; + } + + // + // Print info on multiplexing overhead. + // + + getFramingStats(type, buffer); + + // + // Print stats about additional channels. + // + + getServicesStats(type, buffer); + + // + // Compression summary. + // + + double ratio = 1; + + if (transportData -> compressedBytesOut_ / 1024 > 0) + { + ratio = ((countBitsIn + transportData -> framingBitsOut_) / 8192) / + (transportData -> compressedBytesOut_ / 1024); + + } + else if (countBitsOut > 0) + { + ratio = (countBitsIn + transportData -> framingBitsOut_) / + countBitsOut; + } + + sprintf(format, " Protocol compression ratio is %5.3f:1.\n\n", + ratio); + + strcat(buffer, format); + + getBitrateStats(type, buffer); + + getSplitStats(type, buffer); + + sprintf(format, " %.0f total handled replies (%.0f unmatched).\n\n\n", + countRepliedRequestIn, protocolData -> requestReplied_[X_NXInternalGenericReply]); + + strcat(buffer, format); + + return 1; +} + +int Statistics::getClientOverallStats(int type, char *&buffer) +{ + if (type != PARTIAL_STATS && type != TOTAL_STATS) + { + #ifdef PANIC + *logofs << "Statistics: PANIC! Cannot produce statistics " + << "with qualifier '" << type << "'.\n" + << logofs_flush; + #endif + + return -1; + } + + struct T_overallData *overallData; + struct T_packedData *packedData; + + if (type == PARTIAL_STATS) + { + overallData = &overallPartial_; + packedData = &packedPartial_; + } + else + { + overallData = &overallTotal_; + packedData = &packedTotal_; + } + + char format[FORMAT_LENGTH]; + + // + // Print header including link type, + // followed by info on packed images. + // + + strcat(buffer, "NX Compression Summary\n"); + strcat(buffer, "----------------------\n\n"); + + char label[FORMAT_LENGTH]; + + switch (control -> LinkMode) + { + case LINK_TYPE_NONE: + { + strcpy(label, "NONE"); + + break; + } + case LINK_TYPE_MODEM: + { + strcpy(label, "MODEM"); + + break; + } + case LINK_TYPE_ISDN: + { + strcpy(label, "ISDN"); + + break; + } + case LINK_TYPE_ADSL: + { + strcpy(label, "ADSL"); + + break; + } + case LINK_TYPE_WAN: + { + strcpy(label, "WAN"); + + break; + } + case LINK_TYPE_LAN: + { + strcpy(label, "LAN"); + + break; + } + default: + { + strcpy(label, "Unknown"); + + break; + } + } + + sprintf(format, "link: %s", label); + + if (control -> LocalDeltaCompression == 1) + { + strcat(format, " with protocol compression enabled."); + } + else + { + strcat(format, " with protocol compression disabled."); + } + + strcat(format, "\n\n"); + + strcat(buffer, format); + + if (packedData -> packedBytesIn_ > 0) + { + sprintf(format, "images: %.0f bytes (%.0f KB) packed to %.0f (%.0f KB).\n\n", + packedData -> packedBytesOut_, packedData -> packedBytesOut_ / 1024, + packedData -> packedBytesIn_, packedData -> packedBytesIn_ / 1024); + + strcat(buffer, format); + + sprintf(format, " Images compression ratio is %5.3f:1.\n\n", + packedData -> packedBytesOut_ / packedData -> packedBytesIn_); + + strcat(buffer, format); + } + + double overallIn = overallData -> overallBytesIn_ - packedData -> packedBytesIn_ + + packedData -> packedBytesOut_; + + double overallOut = overallData -> overallBytesOut_; + + sprintf(format, "overall: %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", + overallIn, overallIn / 1024, overallOut, overallOut / 1024); + + strcat(buffer, format); + + if (overallData -> overallBytesOut_ > 0) + { + sprintf(format, " Overall NX server compression ratio is %5.3f:1.\n\n\n", + overallIn / overallOut); + } + else + { + sprintf(format, " Overall NX server compression ratio is 1:1.\n\n\n"); + } + + strcat(buffer, format); + + return 1; +} + +int Statistics::getServerCacheStats(int type, char *&buffer) +{ + if (type != PARTIAL_STATS && type != TOTAL_STATS) + { + #ifdef PANIC + *logofs << "Statistics: PANIC! Cannot produce statistics " + << "with qualifier '" << type << "'.\n" + << logofs_flush; + #endif + + return -1; + } + + // + // Print message cache data according + // to local and remote view. + // + + MessageStore *currentStore = NULL; + MessageStore *anyStore = NULL; + + char format[FORMAT_LENGTH]; + + strcat(buffer, "\nNX Cache Statistics\n"); + strcat(buffer, "-------------------\n\n"); + + for (int m = proxy_client; m <= proxy_server; m++) + { + if (m == proxy_client) + { + strcat(buffer, "Request\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n"); + strcat(buffer, "-------\t------\t--------------\t\t--------------\t\t-----------\n"); + } + else + { + strcat(buffer, "\nReply\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n"); + strcat(buffer, "-----\t------\t--------------\t\t--------------\t\t-----------\n"); + } + + for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++) + { + if (m == proxy_client) + { + currentStore = proxy_ -> getClientStore() -> getRequestStore(i); + } + else + { + currentStore = proxy_ -> getServerStore() -> getReplyStore(i); + } + + if (currentStore != NULL && + (currentStore -> getLocalStorageSize() || + currentStore -> getRemoteStorageSize())) + { + anyStore = currentStore; + + sprintf(format, "#%d\t%d\t", i, currentStore -> getSize()); + + strcat(buffer, format); + + sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getRemoteStorageSize(), + ((double) currentStore -> getRemoteStorageSize()) / 1024); + + strcat(buffer, format); + + sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getLocalStorageSize(), + ((double) currentStore -> getLocalStorageSize()) / 1024); + + strcat(buffer, format); + + sprintf(format, "%d/%.0f KB\n", currentStore -> cacheSlots, + ((double) control -> getUpperStorageSize() / 100 * + currentStore -> cacheThreshold) / 1024); + + strcat(buffer, format); + } + } + + if (anyStore == NULL) + { + strcat(buffer, "N/A\n"); + } + } + + if (anyStore != NULL) + { + sprintf(format, "\ncache: %d bytes (%d KB) available at server.\n", + control -> ClientTotalStorageSize, + control -> ClientTotalStorageSize / 1024); + + strcat(buffer, format); + + sprintf(format, " %d bytes (%d KB) available at client.\n\n", + control -> ServerTotalStorageSize, + control -> ServerTotalStorageSize / 1024); + + strcat(buffer, format); + + sprintf(format, " %d bytes (%d KB) allocated at server.\n", + anyStore -> getRemoteTotalStorageSize(), + anyStore -> getRemoteTotalStorageSize() / 1024); + + strcat(buffer, format); + + sprintf(format, " %d bytes (%d KB) allocated at client.\n\n\n", + anyStore -> getLocalTotalStorageSize(), + anyStore -> getLocalTotalStorageSize() / 1024); + + strcat(buffer, format); + } + else + { + strcat(buffer, "\ncache: N/A\n\n"); + } + + return 1; +} + +int Statistics::getServerProtocolStats(int type, char *&buffer) +{ + if (type != PARTIAL_STATS && type != TOTAL_STATS) + { + #ifdef PANIC + *logofs << "Statistics: PANIC! Cannot produce statistics " + << "with qualifier '" << type << "'.\n" + << logofs_flush; + #endif + + return -1; + } + + struct T_transportData *transportData; + struct T_protocolData *protocolData; + struct T_overallData *overallData; + + if (type == PARTIAL_STATS) + { + transportData = &transportPartial_; + protocolData = &protocolPartial_; + overallData = &overallPartial_; + } + else + { + transportData = &transportTotal_; + protocolData = &protocolTotal_; + overallData = &overallTotal_; + } + + char format[FORMAT_LENGTH]; + + double countReplyBitsIn = 0; + double countReplyBitsOut = 0; + + double countReplyIn = 0; + double countCachedReplyIn = 0; + + double countEventBitsIn = 0; + double countEventBitsOut = 0; + + double countEventIn = 0; + double countCachedEventIn = 0; + + double countAnyIn = 0; + double countBitsIn = 0; + double countBitsOut = 0; + + // + // Print reply data. + // + + strcat(buffer, "NX Client Side Protocol Statistics\n"); + strcat(buffer, "----------------------------------\n\n"); + + strcat(buffer, "Reply Total\tCached\tBits In\t\tBits Out\tBits/Reply\t\tRatio\n"); + strcat(buffer, "------- -----\t------\t-------\t\t--------\t----------\t\t-----\n"); + + for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) + { + if (protocolData -> replyCount_[i]) + { + sprintf(format, "#%d ", i); + + while (strlen(format) < 5) + { + strcat(format, " "); + } + + // + // Mark replies originated + // by NX agent requests. + // + + if (i >= X_NXFirstOpcode && i <= X_NXLastOpcode) + { + strcat(format, "A"); + } + + // + // Mark replies that we didn't + // match against a request. + // + + if (i == 1) + { + strcat(format, "U"); + } + + while (strlen(format) < 8) + { + strcat(format, " "); + } + + strcat(buffer, format); + + if (protocolData -> replyCached_[i] > 0) + { + sprintf(format, "%.0f\t%.0f", protocolData -> replyCount_[i], + protocolData -> replyCached_[i]); + } + else + { + sprintf(format, "%.0f\t", protocolData -> replyCount_[i]); + } + + strcat(buffer, format); + + sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", + protocolData -> replyBitsIn_[i], protocolData -> replyBitsIn_[i] / 8192, + protocolData -> replyBitsOut_[i], protocolData -> replyBitsOut_[i] / 8192, + protocolData -> replyBitsIn_[i] / protocolData -> replyCount_[i], + protocolData -> replyBitsOut_[i] / protocolData -> replyCount_[i]); + + strcat(buffer, format); + + if (protocolData -> replyBitsOut_[i] > 0) + { + sprintf(format, "%5.3f:1\n", protocolData -> replyBitsIn_[i] / + protocolData -> replyBitsOut_[i]); + } + else + { + sprintf(format, "1:1\n"); + } + + strcat(buffer, format); + } + + countReplyIn += protocolData -> replyCount_[i]; + countCachedReplyIn += protocolData -> replyCached_[i]; + + countReplyBitsIn += protocolData -> replyBitsIn_[i]; + countReplyBitsOut += protocolData -> replyBitsOut_[i]; + + countAnyIn += protocolData -> replyCount_[i]; + countBitsIn += protocolData -> replyBitsIn_[i]; + countBitsOut += protocolData -> replyBitsOut_[i]; + } + + if (countReplyIn > 0) + { + if (countCachedReplyIn > 0) + { + sprintf(format, "\ntotal: %.0f\t%.0f", countReplyIn, countCachedReplyIn); + } + else + { + sprintf(format, "\ntotal: %.0f\t", countReplyIn); + } + + strcat(buffer, format); + + sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", + countReplyBitsIn, countReplyBitsIn / 8192, countReplyBitsOut, + countReplyBitsOut / 8192, countReplyBitsIn / countReplyIn, + countReplyBitsOut / countReplyIn); + + strcat(buffer, format); + + if (countReplyBitsOut > 0) + { + sprintf(format, "%5.3f:1\n", countReplyBitsIn / countReplyBitsOut); + } + else + { + sprintf(format, "1:1\n"); + } + + strcat(buffer, format); + } + else + { + strcat(buffer, "N/A\n"); + } + + strcat(buffer, "\n"); + + // + // Print event and error data. + // + + strcat(buffer, "Event Total\tCached\tBits In\t\tBits Out\tBits/Event\t\tRatio\n"); + strcat(buffer, "------- -----\t------\t-------\t\t--------\t----------\t\t-----\n"); + + for (int i = 0; i < STATISTICS_OPCODE_MAX; i++) + { + if (protocolData -> eventCount_[i]) + { + sprintf(format, "#%d ", i); + + while (strlen(format) < 8) + { + strcat(format, " "); + } + + strcat(buffer, format); + + if (protocolData -> eventCached_[i] > 0) + { + sprintf(format, "%.0f\t%.0f", protocolData -> eventCount_[i], + protocolData -> eventCached_[i]); + } + else + { + sprintf(format, "%.0f\t", protocolData -> eventCount_[i]); + } + + strcat(buffer, format); + + sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", + protocolData -> eventBitsIn_[i], protocolData -> eventBitsIn_[i] / 8192, + protocolData -> eventBitsOut_[i], protocolData -> eventBitsOut_[i] / 8192, + protocolData -> eventBitsIn_[i] / protocolData -> eventCount_[i], + protocolData -> eventBitsOut_[i] / protocolData -> eventCount_[i]); + + strcat(buffer, format); + + if (protocolData -> eventBitsOut_[i] > 0) + { + sprintf(format, "%5.3f:1\n", protocolData -> eventBitsIn_[i] / + protocolData -> eventBitsOut_[i]); + } + else + { + sprintf(format, "1:1\n"); + } + + strcat(buffer, format); + } + + countEventIn += protocolData -> eventCount_[i]; + countCachedEventIn += protocolData -> eventCached_[i]; + + countEventBitsIn += protocolData -> eventBitsIn_[i]; + countEventBitsOut += protocolData -> eventBitsOut_[i]; + + countAnyIn += protocolData -> eventCount_[i]; + countBitsIn += protocolData -> eventBitsIn_[i]; + countBitsOut += protocolData -> eventBitsOut_[i]; + } + + if (countEventIn > 0) + { + if (countCachedEventIn > 0) + { + sprintf(format, "\ntotal: %.0f\t%.0f", countEventIn, countCachedEventIn); + } + else + { + sprintf(format, "\ntotal: %.0f\t", countEventIn); + } + + strcat(buffer, format); + + sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t", + countEventBitsIn, countEventBitsIn / 8192, countEventBitsOut, + countEventBitsOut / 8192, countEventBitsIn / countEventIn, + countEventBitsOut / countEventIn); + + strcat(buffer, format); + + if (countEventBitsOut > 0) + { + sprintf(format, "%5.3f:1\n", countEventBitsIn / countEventBitsOut); + } + else + { + sprintf(format, "1:1\n"); + } + + strcat(buffer, format); + } + else + { + strcat(buffer, "N/A\n\n"); + } + + // + // Print transport data. + // + + getTimeStats(type, buffer); + + countAnyIn += protocolData -> cupsCount_; + countBitsIn += protocolData -> cupsBitsIn_; + countBitsOut += protocolData -> cupsBitsOut_; + + countAnyIn += protocolData -> smbCount_; + countBitsIn += protocolData -> smbBitsIn_; + countBitsOut += protocolData -> smbBitsOut_; + + countAnyIn += protocolData -> mediaCount_; + countBitsIn += protocolData -> mediaBitsIn_; + countBitsOut += protocolData -> mediaBitsOut_; + + countAnyIn += protocolData -> httpCount_; + countBitsIn += protocolData -> httpBitsIn_; + countBitsOut += protocolData -> httpBitsOut_; + + countAnyIn += protocolData -> fontCount_; + countBitsIn += protocolData -> fontBitsIn_; + countBitsOut += protocolData -> fontBitsOut_; + + countAnyIn += protocolData -> slaveCount_; + countBitsIn += protocolData -> slaveBitsIn_; + countBitsOut += protocolData -> slaveBitsOut_; + + // + // Save the overall amount of bytes + // coming from X clients. + // + + overallData -> overallBytesIn_ = countBitsIn / 8; + + // + // Print performance data. + // + + if (transportData -> readTime_ > 0) + { + sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n", + countAnyIn / (transportData -> readTime_ / 1000), + (countBitsIn + transportData -> framingBitsOut_) / 8192 / + (transportData -> readTime_ / 1000)); + } + else + { + sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n", + countAnyIn, (countBitsIn + transportData -> + framingBitsOut_) / 8192); + } + + strcat(buffer, format); + + strcat(buffer, "link: "); + + // + // ZLIB compression stats. + // + + getStreamStats(type, buffer); + + // + // Save the overall amount of bytes + // sent on NX proxy link. + // + + if (transportData -> compressedBytesOut_ > 0) + { + overallData -> overallBytesOut_ = transportData -> compressedBytesOut_; + } + else + { + overallData -> overallBytesOut_ = countBitsOut / 8; + } + + // + // Print info on multiplexing overhead. + // + + getFramingStats(type, buffer); + + // + // Print stats about additional channels. + // + + getServicesStats(type, buffer); + + // + // Compression summary. + // + + double ratio = 1; + + if (transportData -> compressedBytesOut_ / 1024 > 0) + { + ratio = ((countBitsIn + transportData -> framingBitsOut_) / 8192) / + (transportData -> compressedBytesOut_ / 1024); + + } + else if (countBitsOut > 0) + { + ratio = (countBitsIn + transportData -> framingBitsOut_) / + countBitsOut; + } + + sprintf(format, " Protocol compression ratio is %5.3f:1.\n\n", + ratio); + + strcat(buffer, format); + + getBitrateStats(type, buffer); + + // + // These are not included in output. + // + // getSplitStats(type, buffer); + // + + strcat(buffer, "\n"); + + // + // These statistics are not included in output. + // You can check it anyway to get the effective + // amount of bytes produced by unpack procedure. + // + // getClientOverallStats(type, buffer); + // + + return 1; +} + +int Statistics::getServerOverallStats(int type, char *&buffer) +{ + return 1; +} + +int Statistics::getTimeStats(int type, char *&buffer) +{ + struct T_transportData *transportData; + + if (type == PARTIAL_STATS) + { + transportData = &transportPartial_; + } + else + { + transportData = &transportTotal_; + } + + char format[FORMAT_LENGTH]; + + sprintf(format, "\ntime: %.0f Ms idle, %.0f Ms (%.0f Ms in read, %.0f Ms in write) running.\n\n", + transportData -> idleTime_, transportData -> readTime_, + transportData -> readTime_ - transportData -> writeTime_, + transportData -> writeTime_); + + strcat(buffer, format); + + return 1; +} + +int Statistics::getStreamStats(int type, char *&buffer) +{ + struct T_transportData *transportData; + + if (type == PARTIAL_STATS) + { + transportData = &transportPartial_; + } + else + { + transportData = &transportTotal_; + } + + char format[FORMAT_LENGTH]; + + if (transportData -> compressedBytesOut_ > 0) + { + sprintf(format, "%.0f bytes (%.0f KB) compressed to %.0f (%.0f KB).\n", + transportData -> compressedBytesIn_, transportData -> compressedBytesIn_ / 1024, + transportData -> compressedBytesOut_, transportData -> compressedBytesOut_ / 1024); + + strcat(buffer, format); + + sprintf(format, " %5.3f:1 stream compression ratio.\n\n", + transportData -> compressedBytesIn_ / transportData -> compressedBytesOut_); + + strcat(buffer, format); + } + + if (transportData -> decompressedBytesOut_ > 0) + { + if (transportData -> compressedBytesOut_ > 0) + { + strcat(buffer, " "); + } + + sprintf(format, "%.0f bytes (%.0f KB) decompressed to %.0f (%.0f KB).\n", + transportData -> decompressedBytesIn_, transportData -> decompressedBytesIn_ / 1024, + transportData -> decompressedBytesOut_, transportData -> decompressedBytesOut_ / 1024); + + strcat(buffer, format); + + sprintf(format, " %5.3f:1 stream compression ratio.\n\n", + transportData -> decompressedBytesOut_ / transportData -> decompressedBytesIn_); + + strcat(buffer, format); + } + + if (transportData -> compressedBytesOut_ > 0 || + transportData -> decompressedBytesOut_ > 0) + { + strcat(buffer, " "); + } + + return 1; +} + +int Statistics::getServicesStats(int type, char *&buffer) +{ + struct T_protocolData *protocolData; + + if (type == PARTIAL_STATS) + { + protocolData = &protocolPartial_; + } + else + { + protocolData = &protocolTotal_; + } + + char format[FORMAT_LENGTH]; + + if (protocolData -> cupsBitsOut_ > 0) + { + sprintf(format, " %.0f CUPS messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", + protocolData -> cupsCount_ , protocolData -> cupsBitsIn_ / 8, + protocolData -> cupsBitsIn_ / 8192, protocolData -> cupsBitsOut_ / 8, + protocolData -> cupsBitsOut_ / 8192); + + strcat(buffer, format); + } + + if (protocolData -> smbBitsOut_ > 0) + { + sprintf(format, " %.0f SMB messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", + protocolData -> smbCount_ , protocolData -> smbBitsIn_ / 8, + protocolData -> smbBitsIn_ / 8192, protocolData -> smbBitsOut_ / 8, + protocolData -> smbBitsOut_ / 8192); + + strcat(buffer, format); + } + + if (protocolData -> mediaBitsOut_ > 0) + { + sprintf(format, " %.0f multimedia messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", + protocolData -> mediaCount_ , protocolData -> mediaBitsIn_ / 8, + protocolData -> mediaBitsIn_ / 8192, protocolData -> mediaBitsOut_ / 8, + protocolData -> mediaBitsOut_ / 8192); + + strcat(buffer, format); + } + + if (protocolData -> httpBitsOut_ > 0) + { + sprintf(format, " %.0f HTTP messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", + protocolData -> httpCount_ , protocolData -> httpBitsIn_ / 8, + protocolData -> httpBitsIn_ / 8192, protocolData -> httpBitsOut_ / 8, + protocolData -> httpBitsOut_ / 8192); + + strcat(buffer, format); + } + + if (protocolData -> fontBitsOut_ > 0) + { + sprintf(format, " %.0f font server messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", + protocolData -> fontCount_ , protocolData -> fontBitsIn_ / 8, + protocolData -> fontBitsIn_ / 8192, protocolData -> fontBitsOut_ / 8, + protocolData -> fontBitsOut_ / 8192); + + strcat(buffer, format); + } + + if (protocolData -> slaveBitsOut_ > 0) + { + sprintf(format, " %.0f slave messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n", + protocolData -> slaveCount_ , protocolData -> slaveBitsIn_ / 8, + protocolData -> slaveBitsIn_ / 8192, protocolData -> slaveBitsOut_ / 8, + protocolData -> slaveBitsOut_ / 8192); + + strcat(buffer, format); + } + + return 1; +} + +int Statistics::getFramingStats(int type, char *&buffer) +{ + struct T_transportData *transportData; + + if (type == PARTIAL_STATS) + { + transportData = &transportPartial_; + } + else + { + transportData = &transportTotal_; + } + + char format[FORMAT_LENGTH]; + + // + // Print info on multiplexing overhead. + // + + sprintf(format, "%.0f frames in, %.0f frames out, %.0f writes out.\n\n", + transportData -> proxyFramesIn_, transportData -> proxyFramesOut_, + transportData -> proxyWritesOut_); + + strcat(buffer, format); + + sprintf(format, " %.0f bytes (%.0f KB) used for framing and multiplexing.\n\n", + transportData -> framingBitsOut_ / 8, transportData -> framingBitsOut_ / 8192); + + strcat(buffer, format); + + return 1; +} + +int Statistics::getBitrateStats(int type, char *&buffer) +{ + struct T_transportData *transportData; + struct T_overallData *overallData; + + if (type == PARTIAL_STATS) + { + transportData = &transportPartial_; + overallData = &overallPartial_; + } + else + { + transportData = &transportTotal_; + overallData = &overallTotal_; + } + + double total = 0; + + if (transportData -> idleTime_ + transportData -> readTime_ > 0) + { + total = overallData -> overallBytesOut_ / + ((transportData -> idleTime_ + transportData -> readTime_) / 1000); + } + + char format[FORMAT_LENGTH]; + + sprintf(format, " %.0f B/s average, %d B/s %ds, %d B/s %ds, %d B/s maximum.\n\n", + total, getBitrateInShortFrame(), control -> ShortBitrateTimeFrame / 1000, + getBitrateInLongFrame(), control -> LongBitrateTimeFrame / 1000, + getTopBitrate()); + + strcat(buffer, format); + + resetTopBitrate(); + + return 1; +} + +int Statistics::getSplitStats(int type, char *&buffer) +{ + // + // Don't print these statistics if persistent + // cache of images is disabled. + // + + if (control -> ImageCacheEnableLoad == 0 && + control -> ImageCacheEnableSave == 0) + { + return 0; + } + + struct T_splitData *splitData; + + if (type == PARTIAL_STATS) + { + splitData = &splitPartial_; + } + else + { + splitData = &splitTotal_; + } + + char format[FORMAT_LENGTH]; + + // + // Print info on split messages restored from disk. + // + + sprintf(format, " %.0f images streamed, %.0f restored, %.0f bytes (%.0f KB) cached.\n\n", + splitData -> splitCount_, splitData -> splitAborted_, splitData -> splitAbortedBytesOut_, + splitData -> splitAbortedBytesOut_ / 1024); + + strcat(buffer, format); + + return 1; +} diff --git a/nxcomp/src/Statistics.h b/nxcomp/src/Statistics.h new file mode 100644 index 000000000..1ffb6b5d6 --- /dev/null +++ b/nxcomp/src/Statistics.h @@ -0,0 +1,745 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Statistics_H +#define Statistics_H + +#include "NXproto.h" + +#include "Misc.h" +#include "Timestamp.h" + +class Proxy; + +// +// Opcode 255 is for generic requests, 1 is for +// generic replies (those which haven't a speci- +// fic differential encoding), opcode 0 is for +// generic messages from the auxiliary channels. +// + +#define STATISTICS_OPCODE_MAX 256 + +// +// Maximum length of the buffer allocated for +// the statistics output. +// + +#define STATISTICS_LENGTH 16384 + +// +// Query type. +// + +#define TOTAL_STATS 1 +#define PARTIAL_STATS 2 +#define NO_STATS 3 + +// +// Log level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Log the operations related to updating +// the control tokens. +// + +#undef TOKEN + +class Statistics +{ + public: + + // + // Use the proxy class to get access + // to the message stores. + // + + Statistics(Proxy *proxy); + + ~Statistics(); + + void addIdleTime(unsigned int numMs) + { + transportPartial_.idleTime_ += numMs; + transportTotal_.idleTime_ += numMs; + } + + void subIdleTime(unsigned int numMs) + { + transportPartial_.idleTime_ -= numMs; + transportTotal_.idleTime_ -= numMs; + } + + void addReadTime(unsigned int numMs) + { + transportPartial_.readTime_ += numMs; + transportTotal_.readTime_ += numMs; + } + + void subReadTime(unsigned int numMs) + { + transportPartial_.readTime_ -= numMs; + transportTotal_.readTime_ -= numMs; + } + + void addWriteTime(unsigned int numMs) + { + transportPartial_.writeTime_ += numMs; + transportTotal_.writeTime_ += numMs; + } + + void subWriteTime(unsigned int numMs) + { + transportPartial_.writeTime_ -= numMs; + transportTotal_.writeTime_ -= numMs; + } + + void addBytesIn(unsigned int numBytes) + { + transportPartial_.proxyBytesIn_ += numBytes; + transportTotal_.proxyBytesIn_ += numBytes; + } + + double getBytesIn() + { + return transportTotal_.proxyBytesIn_; + } + + void addBytesOut(unsigned int numBytes) + { + transportPartial_.proxyBytesOut_ += numBytes; + transportTotal_.proxyBytesOut_ += numBytes; + } + + double getBytesOut() + { + return transportTotal_.proxyBytesOut_; + } + + void addFrameIn() + { + transportPartial_.proxyFramesIn_++; + transportTotal_.proxyFramesIn_++; + + #ifdef TEST + *logofs << "Statistics: Updated total proxy frames in to " + << transportTotal_.proxyFramesIn_ << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + } + + void addFrameOut() + { + transportPartial_.proxyFramesOut_++; + transportTotal_.proxyFramesOut_++; + + #ifdef TEST + *logofs << "Statistics: Updated total proxy frames out to " + << transportTotal_.proxyFramesOut_ << " at " + << strMsTimestamp() << ".\n" + << logofs_flush; + #endif + } + + void addWriteOut() + { + transportPartial_.proxyWritesOut_++; + transportTotal_.proxyWritesOut_++; + + #ifdef TEST + *logofs << "Statistics: Updated total proxy writes out to " + << transportTotal_.proxyWritesOut_ << " at " + << strMsTimestamp() << ".\n" << logofs_flush; + #endif + } + + void addCompressedBytes(unsigned int bytesIn, unsigned int bytesOut); + + void addDecompressedBytes(unsigned int bytesIn, unsigned int bytesOut) + { + transportPartial_.decompressedBytesIn_ += bytesIn; + transportTotal_.decompressedBytesIn_ += bytesIn; + + transportPartial_.decompressedBytesOut_ += bytesOut; + transportTotal_.decompressedBytesOut_ += bytesOut; + } + + void addFramingBits(unsigned int bitsOut) + { + transportPartial_.framingBitsOut_ += bitsOut; + transportTotal_.framingBitsOut_ += bitsOut; + + proxyData_.protocolCount_ += bitsOut; + } + + void addCachedRequest(unsigned int opcode) + { + protocolPartial_.requestCached_[opcode]++; + protocolTotal_.requestCached_[opcode]++; + } + + void addRenderCachedRequest(unsigned int opcode) + { + protocolPartial_.renderRequestCached_[opcode]++; + protocolTotal_.renderRequestCached_[opcode]++; + } + + void addRepliedRequest(unsigned int opcode) + { + protocolPartial_.requestReplied_[opcode]++; + protocolTotal_.requestReplied_[opcode]++; + } + + void addCachedReply(unsigned int opcode) + { + protocolPartial_.replyCached_[opcode]++; + protocolTotal_.replyCached_[opcode]++; + } + + void addRequestBits(unsigned int opcode, unsigned int bitsIn, unsigned int bitsOut) + { + #ifdef DEBUG + *logofs << "Statistcs: Added " << bitsIn << " bits in and " + << bitsOut << " bits out to opcode " << opcode + << ".\n" << logofs_flush; + #endif + + protocolPartial_.requestCount_[opcode]++; + protocolTotal_.requestCount_[opcode]++; + + protocolPartial_.requestBitsIn_[opcode] += bitsIn; + protocolTotal_.requestBitsIn_[opcode] += bitsIn; + + protocolPartial_.requestBitsOut_[opcode] += bitsOut; + protocolTotal_.requestBitsOut_[opcode] += bitsOut; + + // + // Don't account the split bits + // to the control token. + // + + if (opcode != X_NXSplitData && opcode != X_NXSplitEvent) + { + proxyData_.protocolCount_ += bitsOut; + } + } + + void addRenderRequestBits(unsigned int opcode, unsigned int bitsIn, unsigned int bitsOut) + { + #ifdef DEBUG + *logofs << "Statistcs: Added " << bitsIn << " bits in and " + << bitsOut << " bits out to render opcode " << opcode + << ".\n" << logofs_flush; + #endif + + protocolPartial_.renderRequestCount_[opcode]++; + protocolTotal_.renderRequestCount_[opcode]++; + + protocolPartial_.renderRequestBitsIn_[opcode] += bitsIn; + protocolTotal_.renderRequestBitsIn_[opcode] += bitsIn; + + protocolPartial_.renderRequestBitsOut_[opcode] += bitsOut; + protocolTotal_.renderRequestBitsOut_[opcode] += bitsOut; + } + + void addReplyBits(unsigned int opcode, unsigned int bitsIn, unsigned int bitsOut) + { + protocolPartial_.replyCount_[opcode]++; + protocolTotal_.replyCount_[opcode]++; + + protocolPartial_.replyBitsIn_[opcode] += bitsIn; + protocolTotal_.replyBitsIn_[opcode] += bitsIn; + + protocolPartial_.replyBitsOut_[opcode] += bitsOut; + protocolTotal_.replyBitsOut_[opcode] += bitsOut; + + proxyData_.protocolCount_ += bitsOut; + } + + void addEventBits(unsigned int opcode, unsigned int bitsIn, unsigned int bitsOut) + { + protocolPartial_.eventCount_[opcode]++; + protocolTotal_.eventCount_[opcode]++; + + protocolPartial_.eventBitsIn_[opcode] += bitsIn; + protocolTotal_.eventBitsIn_[opcode] += bitsIn; + + protocolPartial_.eventBitsOut_[opcode] += bitsOut; + protocolTotal_.eventBitsOut_[opcode] += bitsOut; + + proxyData_.protocolCount_ += bitsOut; + } + + void addCupsBits(unsigned int bitsIn, unsigned int bitsOut) + { + protocolPartial_.cupsCount_++; + protocolTotal_.cupsCount_++; + + protocolPartial_.cupsBitsIn_ += bitsIn; + protocolTotal_.cupsBitsIn_ += bitsIn; + + protocolPartial_.cupsBitsOut_ += bitsOut; + protocolTotal_.cupsBitsOut_ += bitsOut; + } + + void addSmbBits(unsigned int bitsIn, unsigned int bitsOut) + { + protocolPartial_.smbCount_++; + protocolTotal_.smbCount_++; + + protocolPartial_.smbBitsIn_ += bitsIn; + protocolTotal_.smbBitsIn_ += bitsIn; + + protocolPartial_.smbBitsOut_ += bitsOut; + protocolTotal_.smbBitsOut_ += bitsOut; + } + + void addMediaBits(unsigned int bitsIn, unsigned int bitsOut) + { + protocolPartial_.mediaCount_++; + protocolTotal_.mediaCount_++; + + protocolPartial_.mediaBitsIn_ += bitsIn; + protocolTotal_.mediaBitsIn_ += bitsIn; + + protocolPartial_.mediaBitsOut_ += bitsOut; + protocolTotal_.mediaBitsOut_ += bitsOut; + } + + void addHttpBits(unsigned int bitsIn, unsigned int bitsOut) + { + protocolPartial_.httpCount_++; + protocolTotal_.httpCount_++; + + protocolPartial_.httpBitsIn_ += bitsIn; + protocolTotal_.httpBitsIn_ += bitsIn; + + protocolPartial_.httpBitsOut_ += bitsOut; + protocolTotal_.httpBitsOut_ += bitsOut; + } + + void addFontBits(unsigned int bitsIn, unsigned int bitsOut) + { + protocolPartial_.fontCount_++; + protocolTotal_.fontCount_++; + + protocolPartial_.fontBitsIn_ += bitsIn; + protocolTotal_.fontBitsIn_ += bitsIn; + + protocolPartial_.fontBitsOut_ += bitsOut; + protocolTotal_.fontBitsOut_ += bitsOut; + } + + void addSlaveBits(unsigned int bitsIn, unsigned int bitsOut) + { + protocolPartial_.slaveCount_++; + protocolTotal_.slaveCount_++; + + protocolPartial_.slaveBitsIn_ += bitsIn; + protocolTotal_.slaveBitsIn_ += bitsIn; + + protocolPartial_.slaveBitsOut_ += bitsOut; + protocolTotal_.slaveBitsOut_ += bitsOut; + } + + void addPackedBytesIn(unsigned int numBytes) + { + packedPartial_.packedBytesIn_ += numBytes; + packedTotal_.packedBytesIn_ += numBytes; + } + + void addPackedBytesOut(unsigned int numBytes) + { + packedPartial_.packedBytesOut_ += numBytes; + packedTotal_.packedBytesOut_ += numBytes; + } + + void addSplit() + { + splitPartial_.splitCount_++; + splitTotal_.splitCount_++; + } + + void addSplitAborted() + { + splitPartial_.splitAborted_++; + splitTotal_.splitAborted_++; + } + + void addSplitAbortedBytesOut(unsigned int numBytes) + { + splitPartial_.splitAbortedBytesOut_ += numBytes; + splitTotal_.splitAbortedBytesOut_ += numBytes; + } + + // + // Add the recorded protocol data to the proxy + // token counters. We want to send bpth the token + // request message and the data payload using a + // single system write, so we must guess how many + // output bytes we will generate. + // + + void updateControlToken(int &count) + { + // + // Total is the total number of protocol bytes + // generated so far. We have saved the number + // of bytes generated the last time the function + // was called so we can calculate the difference. + // + // The number of protocol bits is updated as soon + // as new bits are accumulated, to avoid summing + // up all the opcodes in this routine. We add a + // byte to the control bytes difference to account + // for the framing bits that are very likely to + // be added to the payload. + // + + double total = proxyData_.protocolCount_ / 8; + + double diff = total - proxyData_.controlCount_ + 1; + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! Protocol bytes are " + << total << " control bytes are " + << proxyData_.controlCount_ << " difference is " + << diff << ".\n" << logofs_flush; + #endif + + count += (int) (diff / proxyData_.streamRatio_); + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! Adding " + << (int) (diff / proxyData_.streamRatio_) + << " bytes to the control token with ratio " + << proxyData_.streamRatio_ << ".\n" + << logofs_flush; + #endif + + proxyData_.controlCount_ = total; + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! New control token has " + << count << " bytes with total control bytes " + << proxyData_.controlCount_ << ".\n" + << logofs_flush; + #endif + } + + void updateSplitToken(int &count) + { + double total = (protocolTotal_.requestBitsOut_[X_NXSplitData] + + protocolTotal_.eventBitsOut_[X_NXSplitEvent]) / 8; + + double diff = total - proxyData_.splitCount_; + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! Protocol bytes are " + << total << " split bytes are " + << proxyData_.splitCount_ << " difference is " + << diff << ".\n" << logofs_flush; + #endif + + count += (int) (diff / proxyData_.streamRatio_); + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! Adding " + << (int) (diff / proxyData_.streamRatio_) + << " bytes to the split token with ratio " + << proxyData_.streamRatio_ << ".\n" + << logofs_flush; + #endif + + proxyData_.splitCount_ = total; + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! New split token has " + << count << " bytes with total split bytes " + << proxyData_.splitCount_ << ".\n" + << logofs_flush; + #endif + } + + void updateDataToken(int &count) + { + double total = (protocolTotal_.cupsBitsOut_ + + protocolTotal_.smbBitsOut_ + + protocolTotal_.mediaBitsOut_ + + protocolTotal_.httpBitsOut_ + + protocolTotal_.fontBitsOut_ + + protocolTotal_.slaveBitsOut_) / 8; + + double diff = total - proxyData_.dataCount_; + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! Protocol bytes are " + << total << " data bytes are " + << proxyData_.dataCount_ << " difference is " + << diff << ".\n" << logofs_flush; + #endif + + count += (int) (diff / proxyData_.streamRatio_); + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! Adding " + << (int) (diff / proxyData_.streamRatio_) + << " bytes to the data token with ratio " + << proxyData_.streamRatio_ << ".\n" + << logofs_flush; + #endif + + proxyData_.dataCount_ = total; + + #if defined(TEST) || defined(TOKEN) + *logofs << "Statistics: TOKEN! New data token has " + << count << " bytes with total data bytes " + << proxyData_.dataCount_ << ".\n" + << logofs_flush; + #endif + } + + // + // Update the current bitrate. + // + + void updateBitrate(int bytes); + + // + // Return the current bitrate. + // + + int getBitrateInShortFrame() + { + return bitrateInShortFrame_; + } + + int getBitrateInLongFrame() + { + return bitrateInLongFrame_; + } + + int getTopBitrate() + { + return topBitrate_; + } + + void resetTopBitrate() + { + topBitrate_ = 0; + } + + double getStreamRatio() + { + return proxyData_.streamRatio_; + } + + // + // Manage the congestion level. + // + + void updateCongestion(int remaining, int limit); + + double getCongestionInFrame() + { + return congestionInFrame_; + } + + // + // Produce a dump of the statistics on + // the provided buffer. + // + + int getClientCacheStats(int type, char *&buffer); + int getClientProtocolStats(int type, char *&buffer); + int getClientOverallStats(int type, char *&buffer); + + int getServerCacheStats(int type, char *&buffer); + int getServerProtocolStats(int type, char *&buffer); + int getServerOverallStats(int type, char *&buffer); + + int resetPartialStats(); + + private: + + int getTimeStats(int type, char *&buffer); + int getServicesStats(int type, char *&buffer); + int getFramingStats(int type, char *&buffer); + int getBitrateStats(int type, char *&buffer); + int getStreamStats(int type, char *&buffer); + int getSplitStats(int type, char *&buffer); + + struct T_protocolData + { + double requestCached_[STATISTICS_OPCODE_MAX]; + double requestReplied_[STATISTICS_OPCODE_MAX]; + double requestCount_[STATISTICS_OPCODE_MAX]; + double requestBitsIn_[STATISTICS_OPCODE_MAX]; + double requestBitsOut_[STATISTICS_OPCODE_MAX]; + + double renderRequestCached_[STATISTICS_OPCODE_MAX]; + double renderRequestCount_[STATISTICS_OPCODE_MAX]; + double renderRequestBitsIn_[STATISTICS_OPCODE_MAX]; + double renderRequestBitsOut_[STATISTICS_OPCODE_MAX]; + + double replyCached_[STATISTICS_OPCODE_MAX]; + double replyCount_[STATISTICS_OPCODE_MAX]; + double replyBitsIn_[STATISTICS_OPCODE_MAX]; + double replyBitsOut_[STATISTICS_OPCODE_MAX]; + + double eventCached_[STATISTICS_OPCODE_MAX]; + double eventCount_[STATISTICS_OPCODE_MAX]; + double eventBitsIn_[STATISTICS_OPCODE_MAX]; + double eventBitsOut_[STATISTICS_OPCODE_MAX]; + + double cupsCount_; + double cupsBitsIn_; + double cupsBitsOut_; + + double smbCount_; + double smbBitsIn_; + double smbBitsOut_; + + double mediaCount_; + double mediaBitsIn_; + double mediaBitsOut_; + + double httpCount_; + double httpBitsIn_; + double httpBitsOut_; + + double fontCount_; + double fontBitsIn_; + double fontBitsOut_; + + double slaveCount_; + double slaveBitsIn_; + double slaveBitsOut_; + }; + + struct T_transportData + { + double idleTime_; + double readTime_; + double writeTime_; + + double proxyBytesIn_; + double proxyBytesOut_; + + double proxyFramesIn_; + double proxyFramesOut_; + double proxyWritesOut_; + + double compressedBytesIn_; + double compressedBytesOut_; + + double decompressedBytesIn_; + double decompressedBytesOut_; + + double framingBitsOut_; + }; + + struct T_packedData + { + double packedBytesIn_; + double packedBytesOut_; + }; + + struct T_splitData + { + double splitCount_; + double splitAborted_; + double splitAbortedBytesOut_; + }; + + struct T_overallData + { + double overallBytesIn_; + double overallBytesOut_; + }; + + struct T_proxyData + { + double protocolCount_; + double controlCount_; + double splitCount_; + double dataCount_; + + double streamRatio_; + }; + + T_protocolData protocolPartial_; + T_protocolData protocolTotal_; + + T_transportData transportPartial_; + T_transportData transportTotal_; + + T_packedData packedPartial_; + T_packedData packedTotal_; + + T_splitData splitPartial_; + T_splitData splitTotal_; + + T_overallData overallPartial_; + T_overallData overallTotal_; + + T_proxyData proxyData_; + + // + // Used to calculate the bandwidth usage + // of the proxy link. + // + + T_timestamp startShortFrameTs_; + T_timestamp startLongFrameTs_; + T_timestamp startFrameTs_; + + int bytesInShortFrame_; + int bytesInLongFrame_; + + int bitrateInShortFrame_; + int bitrateInLongFrame_; + + int topBitrate_; + + double congestionInFrame_; + + // + // Need the proxy pointer to print the + // statistics related to the client and + // server stores and to add the protocol + // data to the proxy token accumulators. + // + + Proxy *proxy_; +}; + +#endif /* Statistics_H */ diff --git a/nxcomp/src/Timestamp.cpp b/nxcomp/src/Timestamp.cpp new file mode 100644 index 000000000..e7e0c494a --- /dev/null +++ b/nxcomp/src/Timestamp.cpp @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Timestamp.h" + +// +// Log level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Last timestamp taken from the system. +// + +T_timestamp timestamp; + +// +// The following functions all use the ctime +// static buffer from the C library. +// + +char *strTimestamp(const T_timestamp &ts) +{ + char *ctime_now = ctime((time_t *) &ts.tv_sec); + + ctime_now[24] = '\0'; + + return ctime_now; +} + +// +// This is especially dirty. +// + +char *strMsTimestamp(const T_timestamp &ts) +{ + char *ctime_now = ctime((time_t *) &ts.tv_sec); + + char ctime_new[25]; + + sprintf(ctime_new, "%.8s:%3.3f", ctime_now + 11, + (float) ts.tv_usec / 1000); + + strncpy(ctime_now, ctime_new, 24); + + return ctime_now; +} diff --git a/nxcomp/src/Timestamp.h b/nxcomp/src/Timestamp.h new file mode 100644 index 000000000..604f5a3bc --- /dev/null +++ b/nxcomp/src/Timestamp.h @@ -0,0 +1,307 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Timestamp_H +#define Timestamp_H + +#include +#include +#include + +#include +#include + +#include "Misc.h" + +// +// Log level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// If not defined, always query the system time. +// + +#undef CACHE_TIMESTAMP + +// +// Log a warning if the time difference since +// the last update exceeds the given number +// of milliseconds. +// + +#define DRIFT_TIMESTAMP 1 + +// +// Type used for timeout manipulation. +// + +typedef struct timeval T_timestamp; + +// +// Last timestamp taken from the system. If the +// timestamp is cached, we need to explicitly +// get a new timestamp after any operation that +// may have required a relevant amount of time. +// + +extern T_timestamp timestamp; + +// +// Get a timestamp instance with values set +// at the given amount of milliseconds. +// + +inline T_timestamp getTimestamp(long ms) +{ + struct timeval ts; + + ts.tv_sec = ms / 1000; + ts.tv_usec = (ms % 1000) * 1000; + + return ts; +} + +// +// Return the difference in milliseconds +// between the two timestamps. +// + +inline long diffTimestamp(const T_timestamp &ts1, const T_timestamp &ts2) +{ + // + // Add 500 microseconds to round up + // to the nearest millisecond. + // + + return ((ts2.tv_sec * 1000 + (ts2.tv_usec + 500) / 1000) - + (ts1.tv_sec * 1000 + (ts1.tv_usec + 500) / 1000)); +} + +// +// The same in microseconds. It doesn't +// round the value. +// + +inline long diffUsTimestamp(const T_timestamp &ts1, const T_timestamp &ts2) +{ + return ((ts2.tv_sec * 1000000 + ts2.tv_usec) - + (ts1.tv_sec * 1000000 + ts1.tv_usec)); +} + +// +// Return the last timestamp taken from the +// system. It doesn't update the timestamp. +// + +inline T_timestamp getTimestamp() +{ + #ifdef CACHE_TIMESTAMP + + #ifdef TEST + + T_timestamp ts; + + gettimeofday(&ts, NULL); + + long diffTs = diffTimestamp(timestamp, ts); + + if (diffTs > DRIFT_TIMESTAMP) + { + *logofs << "Timestamp: WARNING! Time difference since the " + << "current timestamp is " << diffTs << " Ms.\n" + << logofs_flush; + } + + #endif + + return timestamp; + + #else + + gettimeofday(×tamp, NULL); + + return timestamp; + + #endif +} + +inline T_timestamp &setTimestamp(T_timestamp &ts, long ms) +{ + ts.tv_sec = ms / 1000; + ts.tv_usec = (ms % 1000) * 1000; + + return ts; +} + +// +// Return the smaller between two timestamps. +// + +inline T_timestamp &setMinTimestamp(T_timestamp &ts, long ms) +{ + if ((ts.tv_sec * 1000 + ts.tv_usec / 1000) > ms) + { + ts.tv_sec = ms / 1000; + ts.tv_usec = (ms % 1000) * 1000; + } + + return ts; +} + +inline T_timestamp &setMinTimestamp(T_timestamp &ts1, T_timestamp &ts2) +{ + if ((ts1.tv_sec * 1000000 + ts1.tv_usec) > + (ts2.tv_sec * 1000000 + ts2.tv_usec)) + { + ts1.tv_sec = ts2.tv_sec; + ts1.tv_usec = ts2.tv_usec; + } + + return ts1; +} + +// +// Convert a timestamp in the total number +// of milliseconds. +// + +inline long getMsTimestamp(const T_timestamp &ts) +{ + return ts.tv_sec * 1000 + ts.tv_usec / 1000; +} + +// +// A 0 value on both seconds and microseconds +// fields means that timestamp is invalid or +// not set. +// + +inline T_timestamp nullTimestamp() +{ + struct timeval ts; + + ts.tv_sec = 0; + ts.tv_usec = 0; + + return ts; +} + +inline bool isTimestamp(const T_timestamp &ts) +{ + if (ts.tv_sec == 0 && ts.tv_usec == 0) + { + return 0; + } + + return 1; +} + +inline void subMsTimestamp(T_timestamp &ts, long ms) +{ + ts.tv_sec -= ms / 1000; + ts.tv_usec -= (ms % 1000) * 1000; +} + +inline void addMsTimestamp(T_timestamp &ts, long ms) +{ + ts.tv_sec += ms / 1000; + ts.tv_usec += (ms % 1000) * 1000; +} + +// +// Check the difference between timestamps. +// Return 0 if the system time went backward +// compared to the second timestamp, or the +// difference between the timestamps exceeds +// the given number of milliseconds. +// + +inline int checkDiffTimestamp(const T_timestamp &ts1, const T_timestamp &ts2, + long ms = 30000) +{ + long diffTs = diffTimestamp(ts1, ts2); + + if (diffTs < 0 || diffTs > ms) + { + return 0; + } + + return 1; +} + +// +// Return a string representing the timestamp. +// + +char *strTimestamp(const T_timestamp &ts); +char *strMsTimestamp(const T_timestamp &ts); + +inline char *strTimestamp() +{ + return strTimestamp(getTimestamp()); +} + +inline char *strMsTimestamp() +{ + return strMsTimestamp(getTimestamp()); +} + +// +// Update the current timestamp. +// + +inline T_timestamp getNewTimestamp() +{ + #ifdef TEST + + T_timestamp ts; + + gettimeofday(&ts, NULL); + + *logofs << "Timestamp: Updating the current timestamp at " + << strMsTimestamp(ts) << ".\n" << logofs_flush; + + long diffTs = diffTimestamp(timestamp, ts); + + if (diffTs > DRIFT_TIMESTAMP) + { + *logofs << "Timestamp: WARNING! Time difference since the " + << "old timestamp is " << diffTs << " Ms.\n" + << logofs_flush; + } + + #endif + + gettimeofday(×tamp, NULL); + + return timestamp; +} + +#endif /* Timestamp_H */ diff --git a/nxcomp/src/TranslateCoords.cpp b/nxcomp/src/TranslateCoords.cpp new file mode 100644 index 000000000..f61caea47 --- /dev/null +++ b/nxcomp/src/TranslateCoords.cpp @@ -0,0 +1,115 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "TranslateCoords.h" + +#include "ClientCache.h" + +#include "EncodeBuffer.h" +#include "DecodeBuffer.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Here are the methods to handle messages' content. +// + +int TranslateCoordsStore::parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + TranslateCoordsMessage *translateCoords = (TranslateCoordsMessage *) message; + + // + // Here is the fingerprint. + // + + translateCoords -> src_window = GetULONG(buffer + 4, bigEndian); + translateCoords -> dst_window = GetULONG(buffer + 8, bigEndian); + + translateCoords -> src_x = GetUINT(buffer + 12, bigEndian); + translateCoords -> src_y = GetUINT(buffer + 14, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Parsed Identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +int TranslateCoordsStore::unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + TranslateCoordsMessage *translateCoords = (TranslateCoordsMessage *) message; + + // + // Fill all the message's fields. + // + + PutULONG(translateCoords -> src_window, buffer + 4, bigEndian); + PutULONG(translateCoords -> dst_window, buffer + 8, bigEndian); + + PutUINT(translateCoords -> src_x, buffer + 12, bigEndian); + PutUINT(translateCoords -> src_y, buffer + 14, bigEndian); + + #ifdef DEBUG + *logofs << name() << ": Unparsed identity for message at " << this << ".\n" << logofs_flush; + #endif + + return 1; +} + +void TranslateCoordsStore::dumpIdentity(const Message *message) const +{ + #ifdef DUMP + + TranslateCoordsMessage *translateCoords = (TranslateCoordsMessage *) message; + + *logofs << name() << ": Identity src_window " << translateCoords -> src_window << ", dst_window " + << translateCoords -> dst_window << ", src_x " << translateCoords -> src_x << ", src_y " + << translateCoords -> src_y << ", size " << translateCoords -> size_ << ".\n" << logofs_flush; + + #endif +} + +void TranslateCoordsStore::identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const +{ + md5_append(md5_state_, buffer + 4, 4); + md5_append(md5_state_, buffer + 8, 4); + md5_append(md5_state_, buffer + 12, 2); + md5_append(md5_state_, buffer + 14, 2); +} diff --git a/nxcomp/src/TranslateCoords.h b/nxcomp/src/TranslateCoords.h new file mode 100644 index 000000000..997d079e1 --- /dev/null +++ b/nxcomp/src/TranslateCoords.h @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef TranslateCoords_H +#define TranslateCoords_H + +#include "Message.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +// +// Set default values. +// + +#define TRANSLATECOORDS_ENABLE_CACHE 1 +#define TRANSLATECOORDS_ENABLE_DATA 0 +#define TRANSLATECOORDS_ENABLE_SPLIT 0 +#define TRANSLATECOORDS_ENABLE_COMPRESS 0 + +#define TRANSLATECOORDS_DATA_LIMIT 0 +#define TRANSLATECOORDS_DATA_OFFSET 16 + +#define TRANSLATECOORDS_CACHE_SLOTS 3000 +#define TRANSLATECOORDS_CACHE_THRESHOLD 3 +#define TRANSLATECOORDS_CACHE_LOWER_THRESHOLD 1 + +// +// The message class. +// + +class TranslateCoordsMessage : public Message +{ + friend class TranslateCoordsStore; + + public: + + TranslateCoordsMessage() + { + } + + ~TranslateCoordsMessage() + { + } + + // + // Put here the fields which constitute + // the 'identity' part of the message. + // + + private: + + unsigned int src_window; + unsigned int dst_window; + unsigned int src_x; + unsigned int src_y; + + unsigned char r_same_screen; + unsigned int r_child_window; + unsigned int r_dst_x; + unsigned int r_dst_y; +}; + +class TranslateCoordsStore : public MessageStore +{ + // + // Constructors and destructors. + // + + public: + + TranslateCoordsStore() : MessageStore() + { + enableCache = TRANSLATECOORDS_ENABLE_CACHE; + enableData = TRANSLATECOORDS_ENABLE_DATA; + enableSplit = TRANSLATECOORDS_ENABLE_SPLIT; + enableCompress = TRANSLATECOORDS_ENABLE_COMPRESS; + + dataLimit = TRANSLATECOORDS_DATA_LIMIT; + dataOffset = TRANSLATECOORDS_DATA_OFFSET; + + cacheSlots = TRANSLATECOORDS_CACHE_SLOTS; + cacheThreshold = TRANSLATECOORDS_CACHE_THRESHOLD; + cacheLowerThreshold = TRANSLATECOORDS_CACHE_LOWER_THRESHOLD; + + messages_ -> resize(cacheSlots); + + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + *i = NULL; + } + + temporary_ = NULL; + } + + virtual ~TranslateCoordsStore() + { + for (T_messages::iterator i = messages_ -> begin(); + i < messages_ -> end(); i++) + { + destroy(*i); + } + + destroy(temporary_); + } + + virtual const char *name() const + { + return "TranslateCoords"; + } + + virtual unsigned char opcode() const + { + return X_TranslateCoords; + } + + virtual unsigned int storage() const + { + return sizeof(TranslateCoordsMessage); + } + + // + // Message handling methods. + // + + public: + + virtual Message *create() const + { + return new TranslateCoordsMessage(); + } + + virtual Message *create(const Message &message) const + { + return new TranslateCoordsMessage((const TranslateCoordsMessage &) message); + } + + virtual void destroy(Message *message) const + { + delete (TranslateCoordsMessage *) message; + } + + virtual int parseIdentity(Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual int unparseIdentity(const Message *message, unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void identityChecksum(const Message *message, const unsigned char *buffer, + unsigned int size, int bigEndian) const; + + virtual void dumpIdentity(const Message *message) const; +}; + +#endif /* TranslateCoords_H */ diff --git a/nxcomp/src/Transport.cpp b/nxcomp/src/Transport.cpp new file mode 100644 index 000000000..e34544994 --- /dev/null +++ b/nxcomp/src/Transport.cpp @@ -0,0 +1,3068 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "Transport.h" + +#include "Statistics.h" + +// +// Set the verbosity level. You also +// need to define DUMP in Misc.cpp +// if DUMP is defined here. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef INSPECT +#undef DUMP + +// +// Used to lock and unlock the transport +// buffers before they are accessed by +// different threads. +// + +#undef THREADS + +// +// Define this to get logging all the +// operations performed by the parent +// thread, the one that enqueues and +// dequeues data. +// + +#define PARENT + +// +// Define this to know when a channel +// is created or destroyed. +// + +#undef REFERENCES + +// +// Reference count for allocated buffers. +// + +#ifdef REFERENCES + +int Transport::references_; +int ProxyTransport::references_; +int InternalTransport::references_; + +#endif + +// +// This is the base class providing methods for read +// and write buffering. +// + +Transport::Transport(int fd) : fd_(fd) +{ + #ifdef TEST + *logofs << "Transport: Going to create base transport " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + type_ = transport_base; + + // + // Set up the write buffer. + // + + w_buffer_.length_ = 0; + w_buffer_.start_ = 0; + + initialSize_ = TRANSPORT_BUFFER_DEFAULT_SIZE; + thresholdSize_ = TRANSPORT_BUFFER_DEFAULT_SIZE << 1; + maximumSize_ = TRANSPORT_BUFFER_DEFAULT_SIZE << 4; + + w_buffer_.data_.resize(initialSize_); + + // + // Set non-blocking IO on socket. + // + + SetNonBlocking(fd_, 1); + + blocked_ = 0; + finish_ = 0; + + #ifdef REFERENCES + *logofs << "Transport: Created new object at " + << this << " out of " << ++references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +Transport::~Transport() +{ + #ifdef TEST + *logofs << "Transport: Going to destroy base class " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + ::close(fd_); + + #ifdef REFERENCES + *logofs << "Transport: Deleted object at " + << this << " out of " << --references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +// +// Read data from its file descriptor. +// + +int Transport::read(unsigned char *data, unsigned int size) +{ + #ifdef DEBUG + *logofs << "Transport: Going to read " << size << " bytes from " + << "FD#" << fd_ << ".\n" << logofs_flush; + #endif + + // + // Read the available data from the socket. + // + + int result = ::read(fd_, data, size); + + // + // Update the current timestamp as the read + // can have scheduled some other process. + // + + getNewTimestamp(); + + if (result < 0) + { + if (EGET() == EAGAIN) + { + #ifdef TEST + *logofs << "Transport: WARNING! Read of " << size << " bytes from " + << "FD#" << fd_ << " would block.\n" << logofs_flush; + #endif + + return 0; + } + else if (EGET() == EINTR) + { + #ifdef TEST + *logofs << "Transport: Read of " << size << " bytes from " + << "FD#" << fd_ << " was interrupted.\n" + << logofs_flush; + #endif + + return 0; + } + else + { + #ifdef TEST + *logofs << "Transport: Error reading from " + << "FD#" << fd_ << ".\n" << logofs_flush; + #endif + + finish(); + + return -1; + } + } + else if (result == 0) + { + #ifdef TEST + *logofs << "Transport: No data read from " + << "FD#" << fd_ << ".\n" << logofs_flush; + #endif + + finish(); + + return -1; + } + + #ifdef TEST + *logofs << "Transport: Read " << result << " bytes out of " + << size << " from FD#" << fd_ << ".\n" << logofs_flush; + #endif + + #ifdef DUMP + + *logofs << "Transport: Dumping content of read data.\n" + << logofs_flush; + + DumpData(data, result); + + #endif + + return result; +} + +// +// Write as many bytes as possible to socket. +// Append the remaining data bytes to the end +// of the buffer and update length to reflect +// changes. +// + +int Transport::write(T_write type, const unsigned char *data, const unsigned int size) +{ + // + // If an immediate write was requested then + // flush the enqueued data first. + // + // Alternatively may try to write only if + // the socket is not blocked. + // + // if (w_buffer_.length_ > 0 && blocked_ == 0 && + // type == write_immediate) + // { + // ... + // } + // + + if (w_buffer_.length_ > 0 && type == write_immediate) + + { + #ifdef TEST + *logofs << "Transport: Writing " << w_buffer_.length_ + << " bytes of previous data to FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + int result = Transport::flush(); + + if (result < 0) + { + return -1; + } + } + + // + // If nothing is remained, write immediately + // to the socket. + // + + unsigned int written = 0; + + if (w_buffer_.length_ == 0 && blocked_ == 0 && + type == write_immediate) + { + // + // Limit the amount of data sent. + // + + unsigned int toWrite = size; + + #ifdef DUMP + + *logofs << "Transport: Going to write " << toWrite + << " bytes to FD#" << fd_ << " with checksum "; + + DumpChecksum(data, size); + + *logofs << ".\n" << logofs_flush; + + #endif + + T_timestamp writeTs; + + int diffTs; + + while (written < toWrite) + { + // + // Trace system time spent writing data. + // + + writeTs = getTimestamp(); + + int result = ::write(fd_, data + written, toWrite - written); + + diffTs = diffTimestamp(writeTs, getNewTimestamp()); + + statistics -> addWriteTime(diffTs); + + if (result <= 0) + { + if (EGET() == EAGAIN) + { + #ifdef TEST + *logofs << "Transport: Write of " << toWrite - written + << " bytes on FD#" << fd_ << " would block.\n" + << logofs_flush; + #endif + + blocked_ = 1; + + break; + } + else if (EGET() == EINTR) + { + #ifdef TEST + *logofs << "Transport: Write of " << toWrite - written + << " bytes on FD#" << fd_ << " was interrupted.\n" + << logofs_flush; + #endif + + continue; + } + else + { + #ifdef TEST + *logofs << "Transport: Write to " << "FD#" + << fd_ << " failed.\n" << logofs_flush; + #endif + + finish(); + + return -1; + } + } + else + { + #ifdef TEST + *logofs << "Transport: Immediately written " << result + << " bytes on " << "FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + written += result; + } + } + + #ifdef DUMP + + if (written > 0) + { + *logofs << "Transport: Dumping content of immediately written data.\n" + << logofs_flush; + + DumpData(data, written); + } + + #endif + } + + if (written == size) + { + // + // We will not affect the write buffer. + // + + return written; + } + + #ifdef DEBUG + *logofs << "Transport: Going to append " << size - written + << " bytes to write buffer for " << "FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + if (resize(w_buffer_, size - written) < 0) + { + return -1; + } + + memmove(w_buffer_.data_.begin() + w_buffer_.start_ + w_buffer_.length_, + data + written, size - written); + + w_buffer_.length_ += size - written; + + #ifdef TEST + *logofs << "Transport: Write buffer for FD#" << fd_ + << " has data for " << w_buffer_.length_ << " bytes.\n" + << logofs_flush; + + *logofs << "Transport: Start is " << w_buffer_.start_ + << " length is " << w_buffer_.length_ << " size is " + << w_buffer_.data_.size() << " capacity is " + << w_buffer_.data_.capacity() << ".\n" + << logofs_flush; + #endif + + // + // Note that this function always returns the whole + // size of buffer that was provided, either if not + // all the data could be actually written. + // + + return size; +} + +// +// Write pending data to its file descriptor. +// + +int Transport::flush() +{ + if (w_buffer_.length_ == 0) + { + #ifdef TEST + *logofs << "Transport: No data to flush on " + << "FD#" << fd_ << ".\n" << logofs_flush; + #endif + + #ifdef WARNING + if (blocked_ != 0) + { + *logofs << "Transport: Blocked flag is " << blocked_ + << " with no data to flush on FD#" << fd_ + << ".\n" << logofs_flush; + } + #endif + + return 0; + } + + // + // It's time to move data from the + // write buffer to the real link. + // + + int written = 0; + + int toWrite = w_buffer_.length_; + + // + // We will do our best to write any available + // data to the socket, so let's say we start + // from a clean state. + // + + blocked_ = 0; + + #ifdef TEST + *logofs << "Transport: Going to flush " << toWrite + << " bytes on FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + T_timestamp writeTs; + + int diffTs; + + while (written < toWrite) + { + writeTs = getTimestamp(); + + int result = ::write(fd_, w_buffer_.data_.begin() + w_buffer_.start_ + + written, toWrite - written); + + diffTs = diffTimestamp(writeTs, getNewTimestamp()); + + statistics -> addWriteTime(diffTs); + + if (result <= 0) + { + if (EGET() == EAGAIN) + { + #ifdef TEST + *logofs << "Transport: Write of " << toWrite - written + << " bytes on FD#" << fd_ << " would block.\n" + << logofs_flush; + #endif + + blocked_ = 1; + + break; + } + else if (EGET() == EINTR) + { + #ifdef TEST + *logofs << "Transport: Write of " << toWrite - written + << " bytes on FD#" << fd_ << " was interrupted.\n" + << logofs_flush; + #endif + + continue; + } + else + { + #ifdef TEST + *logofs << "Transport: Write to " << "FD#" + << fd_ << " failed.\n" << logofs_flush; + #endif + + finish(); + + return -1; + } + } + else + { + #ifdef TEST + *logofs << "Transport: Flushed " << result << " bytes on " + << "FD#" << fd_ << ".\n" << logofs_flush; + #endif + + written += result; + } + } + + if (written > 0) + { + #ifdef DUMP + + *logofs << "Transport: Dumping content of flushed data.\n" + << logofs_flush; + + DumpData(w_buffer_.data_.begin() + w_buffer_.start_, written); + + #endif + + // + // Update the buffer status. + // + + w_buffer_.length_ -= written; + + if (w_buffer_.length_ == 0) + { + w_buffer_.start_ = 0; + } + else + { + w_buffer_.start_ += written; + } + } + + // + // It can be that we wrote less bytes than + // available because of the write limit. + // + + if (w_buffer_.length_ > 0) + { + #ifdef TEST + *logofs << "Transport: There are still " << w_buffer_.length_ + << " bytes in write buffer for " << "FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + blocked_ = 1; + } + + #ifdef TEST + *logofs << "Transport: Write buffer for FD#" << fd_ + << " has data for " << w_buffer_.length_ << " bytes.\n" + << logofs_flush; + + *logofs << "Transport: Start is " << w_buffer_.start_ + << " length is " << w_buffer_.length_ << " size is " + << w_buffer_.data_.size() << " capacity is " + << w_buffer_.data_.capacity() << ".\n" + << logofs_flush; + #endif + + // + // No new data was produced for the link except + // any outstanding data from previous writes. + // + + return 0; +} + +int Transport::drain(int limit, int timeout) +{ + if (w_buffer_.length_ <= limit) + { + return 1; + } + + // + // Write the data accumulated in the write + // buffer until it is below the limit or + // the timeout is elapsed. + // + + int toWrite = w_buffer_.length_; + + int written = 0; + + #ifdef TEST + *logofs << "Transport: Draining " << toWrite - limit + << " bytes on FD#" << fd_ << " with limit set to " + << limit << ".\n" << logofs_flush; + #endif + + T_timestamp startTs = getNewTimestamp(); + + T_timestamp selectTs; + T_timestamp writeTs; + T_timestamp idleTs; + + T_timestamp nowTs = startTs; + + int diffTs; + + fd_set writeSet; + fd_set readSet; + + FD_ZERO(&writeSet); + FD_ZERO(&readSet); + + int result; + int ready; + + while (w_buffer_.length_ - written > limit) + { + nowTs = getNewTimestamp(); + + // + // Wait for descriptor to become + // readable or writable. + // + + FD_SET(fd_, &writeSet); + FD_SET(fd_, &readSet); + + setTimestamp(selectTs, timeout / 2); + + idleTs = nowTs; + + result = select(fd_ + 1, &readSet, &writeSet, NULL, &selectTs); + + nowTs = getNewTimestamp(); + + diffTs = diffTimestamp(idleTs, nowTs); + + statistics -> addIdleTime(diffTs); + + statistics -> subReadTime(diffTs); + + if (result < 0) + { + if (EGET() == EINTR) + { + #ifdef TEST + *logofs << "Transport: Select on FD#" << fd_ + << " was interrupted.\n" << logofs_flush; + #endif + + continue; + } + else + { + #ifdef TEST + *logofs << "Transport: Select on FD#" << fd_ + << " failed.\n" << logofs_flush; + #endif + + finish(); + + return -1; + } + } + else if (result > 0) + { + ready = result; + + if (FD_ISSET(fd_, &writeSet)) + { + writeTs = getNewTimestamp(); + + result = ::write(fd_, w_buffer_.data_.begin() + w_buffer_.start_ + + written, toWrite - written); + + nowTs = getNewTimestamp(); + + diffTs = diffTimestamp(writeTs, nowTs); + + statistics -> addWriteTime(diffTs); + + if (result > 0) + { + #ifdef TEST + *logofs << "Transport: Forced flush of " << result + << " bytes on " << "FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + written += result; + } + else if (result < 0 && EGET() == EINTR) + { + #ifdef TEST + *logofs << "Transport: Write to FD#" << fd_ + << " was interrupted.\n" << logofs_flush; + #endif + + continue; + } + else + { + #ifdef TEST + *logofs << "Transport: Write to FD#" << fd_ + << " failed.\n" << logofs_flush; + #endif + + finish(); + + return -1; + } + + ready--; + } + + if (ready > 0) + { + if (FD_ISSET(fd_, &readSet)) + { + #ifdef TEST + *logofs << "Transport: Not draining further " + << "due to data readable on FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + break; + } + } + } + #ifdef TEST + else + { + *logofs << "Transport: Timeout encountered " + << "waiting for FD#" << fd_ << ".\n" + << logofs_flush; + } + #endif + + nowTs = getNewTimestamp(); + + diffTs = diffTimestamp(startTs, nowTs); + + if (diffTs >= timeout) + { + #ifdef TEST + *logofs << "Transport: Not draining further " + << "due to the timeout on FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + break; + } + } + + if (written > 0) + { + #ifdef DUMP + + *logofs << "Transport: Dumping content of flushed data.\n" + << logofs_flush; + + DumpData(w_buffer_.data_.begin() + w_buffer_.start_, written); + + #endif + + // + // Update the buffer status. + // + + w_buffer_.length_ -= written; + + if (w_buffer_.length_ == 0) + { + w_buffer_.start_ = 0; + + blocked_ = 0; + } + else + { + w_buffer_.start_ += written; + + #ifdef TEST + *logofs << "Transport: There are still " << w_buffer_.length_ + << " bytes in write buffer for " << "FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + blocked_ = 1; + } + } + #ifdef TEST + else + { + *logofs << "Transport: WARNING! No data written to FD#" << fd_ + << " with " << toWrite << " bytes to drain and limit " + << "set to " << limit << ".\n" << logofs_flush; + } + #endif + + #ifdef TEST + *logofs << "Transport: Write buffer for FD#" << fd_ + << " has data for " << w_buffer_.length_ << " bytes.\n" + << logofs_flush; + + *logofs << "Transport: Start is " << w_buffer_.start_ + << " length is " << w_buffer_.length_ << " size is " + << w_buffer_.data_.size() << " capacity is " + << w_buffer_.data_.capacity() << ".\n" + << logofs_flush; + #endif + + return (w_buffer_.length_ <= limit); +} + +int Transport::wait(int timeout) const +{ + T_timestamp startTs = getNewTimestamp(); + + T_timestamp idleTs; + T_timestamp selectTs; + + T_timestamp nowTs = startTs; + + long available = 0; + int result = 0; + + int diffTs; + + fd_set readSet; + + FD_ZERO(&readSet); + FD_SET(fd_, &readSet); + + for (;;) + { + available = readable(); + + diffTs = diffTimestamp(startTs, nowTs); + + if (available != 0 || timeout == 0 || + (diffTs + (timeout / 10)) >= timeout) + { + #ifdef TEST + *logofs << "Transport: There are " << available + << " bytes on FD#" << fd_ << " after " + << diffTs << " Ms.\n" << logofs_flush; + #endif + + return available; + } + else if (available == 0 && result > 0) + { + #ifdef TEST + *logofs << "Transport: Read on " << "FD#" + << fd_ << " failed.\n" << logofs_flush; + #endif + + return -1; + } + + // + // TODO: Should subtract the time + // already spent in select. + // + + selectTs.tv_sec = 0; + selectTs.tv_usec = timeout * 1000; + + idleTs = nowTs; + + // + // Wait for descriptor to become readable. + // + + result = select(fd_ + 1, &readSet, NULL, NULL, &selectTs); + + nowTs = getNewTimestamp(); + + diffTs = diffTimestamp(idleTs, nowTs); + + statistics -> addIdleTime(diffTs); + + statistics -> subReadTime(diffTs); + + if (result < 0) + { + if (EGET() == EINTR) + { + #ifdef TEST + *logofs << "Transport: Select on FD#" << fd_ + << " was interrupted.\n" << logofs_flush; + #endif + + continue; + } + else + { + #ifdef TEST + *logofs << "Transport: Select on " << "FD#" + << fd_ << " failed.\n" << logofs_flush; + #endif + + return -1; + } + } + #ifdef TEST + else if (result == 0) + { + *logofs << "Transport: No data available on FD#" << fd_ + << " after " << diffTimestamp(startTs, nowTs) + << " Ms.\n" << logofs_flush; + } + else + { + *logofs << "Transport: Data became available on FD#" << fd_ + << " after " << diffTimestamp(startTs, nowTs) + << " Ms.\n" << logofs_flush; + } + #endif + } +} + +void Transport::setSize(unsigned int initialSize, unsigned int thresholdSize, + unsigned int maximumSize) +{ + initialSize_ = initialSize; + thresholdSize_ = thresholdSize; + maximumSize_ = maximumSize; + + #ifdef TEST + *logofs << "Transport: Set buffer sizes for FD#" << fd_ + << " to " << initialSize_ << "/" << thresholdSize_ + << "/" << maximumSize_ << ".\n" << logofs_flush; + #endif +} + +void Transport::fullReset() +{ + blocked_ = 0; + finish_ = 0; + + fullReset(w_buffer_); +} + +int Transport::resize(T_buffer &buffer, const int &size) +{ + if ((int) buffer.data_.size() >= (buffer.length_ + size) && + (buffer.start_ + buffer.length_ + size) > + (int) buffer.data_.size()) + { + if (buffer.length_ > 0) + { + // + // There is enough space in buffer but we need + // to move existing data at the beginning. + // + + #ifdef TEST + *logofs << "Transport: Moving " << buffer.length_ + << " bytes of data for " << "FD#" << fd_ + << " to make room in the buffer.\n" + << logofs_flush; + #endif + + memmove(buffer.data_.begin(), buffer.data_.begin() + + buffer.start_, buffer.length_); + } + + buffer.start_ = 0; + + #ifdef DEBUG + *logofs << "Transport: Made room for " + << buffer.data_.size() - buffer.start_ + << " bytes in buffer for " << "FD#" + << fd_ << ".\n" << logofs_flush; + #endif + } + else if ((buffer.length_ + size) > (int) buffer.data_.size()) + { + // + // Not enough space, so increase + // the size of the buffer. + // + + if (buffer.start_ != 0 && buffer.length_ > 0) + { + #ifdef TEST + *logofs << "Transport: Moving " << buffer.length_ + << " bytes of data for " << "FD#" << fd_ + << " to resize the buffer.\n" + << logofs_flush; + #endif + + memmove(buffer.data_.begin(), buffer.data_.begin() + + buffer.start_, buffer.length_); + } + + buffer.start_ = 0; + + unsigned int newSize = thresholdSize_; + + while (newSize < (unsigned int) buffer.length_ + size) + { + newSize <<= 1; + + if (newSize >= maximumSize_) + { + newSize = buffer.length_ + size + initialSize_; + } + } + + #ifdef DEBUG + *logofs << "Transport: Buffer for " << "FD#" << fd_ + << " will be enlarged from " << buffer.data_.size() + << " to at least " << buffer.length_ + size + << " bytes.\n" << logofs_flush; + #endif + + buffer.data_.resize(newSize); + + #ifdef TEST + if (newSize >= maximumSize_) + { + *logofs << "Transport: WARNING! Buffer for FD#" << fd_ + << " grown to reach size of " << newSize + << " bytes.\n" << logofs_flush; + } + #endif + + #ifdef TEST + *logofs << "Transport: Data buffer for " << "FD#" + << fd_ << " has now size " << buffer.data_.size() + << " and capacity " << buffer.data_.capacity() + << ".\n" << logofs_flush; + #endif + } + + return (buffer.length_ + size); +} + +void Transport::fullReset(T_buffer &buffer) +{ + // + // Force deallocation and allocation + // of the initial size. + // + + #ifdef TEST + *logofs << "Transport: Resetting buffer for " << "FD#" + << fd_ << " with size " << buffer.data_.size() + << " and capacity " << buffer.data_.capacity() + << ".\n" << logofs_flush; + #endif + + buffer.start_ = 0; + buffer.length_ = 0; + + if (buffer.data_.size() > (unsigned int) initialSize_ && + buffer.data_.capacity() > (unsigned int) initialSize_) + { + buffer.data_.clear(); + + buffer.data_.resize(initialSize_); + + #ifdef TEST + *logofs << "Transport: Data buffer for " << "FD#" + << fd_ << " shrunk to size " << buffer.data_.size() + << " and capacity " << buffer.data_.capacity() + << ".\n" << logofs_flush; + #endif + } +} + +ProxyTransport::ProxyTransport(int fd) : Transport(fd) +{ + #ifdef TEST + *logofs << "ProxyTransport: Going to create proxy transport " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + type_ = transport_proxy; + + // + // Set up the read buffer. + // + + r_buffer_.length_ = 0; + r_buffer_.start_ = 0; + + r_buffer_.data_.resize(initialSize_); + + // + // For now we own the buffer. + // + + owner_ = 1; + + // + // Set up ZLIB compression. + // + + int result; + + r_stream_.zalloc = NULL; + r_stream_.zfree = NULL; + r_stream_.opaque = NULL; + + r_stream_.next_in = NULL; + r_stream_.avail_in = 0; + + if ((result = inflateInit2(&r_stream_, 15)) != Z_OK) + { + #ifdef PANIC + *logofs << "ProxyTransport: PANIC! Failed initialization of ZLIB read stream. " + << "Error is '" << zError(result) << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed initialization of ZLIB read stream. " + << "Error is '" << zError(result) << "'.\n"; + + HandleCleanup(); + } + + if (control -> LocalStreamCompression) + { + w_stream_.zalloc = NULL; + w_stream_.zfree = NULL; + w_stream_.opaque = NULL; + + if ((result = deflateInit2(&w_stream_, control -> LocalStreamCompressionLevel, Z_DEFLATED, + 15, 9, Z_DEFAULT_STRATEGY)) != Z_OK) + { + #ifdef PANIC + *logofs << "ProxyTransport: PANIC! Failed initialization of ZLIB write stream. " + << "Error is '" << zError(result) << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Failed initialization of ZLIB write stream. " + << "Error is '" << zError(result) << "'.\n"; + + HandleCleanup(); + } + } + + // + // No ZLIB stream to flush yet. + // + + flush_ = 0; + + #ifdef REFERENCES + *logofs << "ProxyTransport: Created new object at " + << this << " out of " << ++references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +ProxyTransport::~ProxyTransport() +{ + #ifdef TEST + *logofs << "ProxyTransport: Going to destroy derived class " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + // + // Deallocate the ZLIB stream state. + // + + inflateEnd(&r_stream_); + + if (control -> LocalStreamCompression) + { + deflateEnd(&w_stream_); + } + + #ifdef REFERENCES + *logofs << "ProxyTransport: Deleted object at " + << this << " out of " << --references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +// +// Read data from its file descriptor. +// + +int ProxyTransport::read(unsigned char *data, unsigned int size) +{ + // + // If the remote peer is not compressing + // the stream then just return any byte + // read from the socket. + // + + if (control -> RemoteStreamCompression == 0) + { + int result = Transport::read(data, size); + + if (result <= 0) + { + return result; + } + + statistics -> addBytesIn(result); + + return result; + } + + // + // Return any pending data first. + // + + if (r_buffer_.length_ > 0) + { + // + // If the size of the buffer doesn't + // match the amount of data pending, + // force the caller to retry. + // + + if ((int) size < r_buffer_.length_) + { + #ifdef TEST + *logofs << "ProxyTransport: WARNING! Forcing a retry with " + << r_buffer_.length_ << " bytes pending and " + << size << " in the buffer.\n" + << logofs_flush; + #endif + + ESET(EAGAIN); + + return -1; + } + + int copied = (r_buffer_.length_ > ((int) size) ? + ((int) size) : r_buffer_.length_); + + memcpy(data, r_buffer_.data_.begin() + r_buffer_.start_, copied); + + // + // Update the buffer status. + // + + #ifdef DEBUG + *logofs << "ProxyTransport: Going to immediately return " << copied + << " bytes from proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + r_buffer_.length_ -= copied; + + if (r_buffer_.length_ == 0) + { + r_buffer_.start_ = 0; + } + else + { + r_buffer_.start_ += copied; + + #ifdef TEST + *logofs << "ProxyTransport: There are still " << r_buffer_.length_ + << " bytes in read buffer for proxy " << "FD#" + << fd_ << ".\n" << logofs_flush; + #endif + } + + return copied; + } + + // + // Read data in the user buffer. + // + + int result = Transport::read(data, size); + + if (result <= 0) + { + return result; + } + + statistics -> addBytesIn(result); + + // + // Decompress the data into the read + // buffer. + // + + #ifdef DEBUG + *logofs << "ProxyTransport: Going to decompress data for " + << "proxy FD#" << fd_ << ".\n" << logofs_flush; + #endif + + int saveTotalIn = r_stream_.total_in; + int saveTotalOut = r_stream_.total_out; + + int oldTotalIn = saveTotalIn; + int oldTotalOut = saveTotalOut; + + int diffTotalIn; + int diffTotalOut; + + #ifdef INSPECT + *logofs << "ProxyTransport: oldTotalIn = " << oldTotalIn + << ".\n" << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: oldTotalOut = " << oldTotalOut + << ".\n" << logofs_flush; + #endif + + r_stream_.next_in = (Bytef *) data; + r_stream_.avail_in = result; + + // + // Let ZLIB use all the space already + // available in the buffer. + // + + unsigned int newAvailOut = r_buffer_.data_.size() - r_buffer_.start_ - + r_buffer_.length_; + + #ifdef TEST + *logofs << "ProxyTransport: Initial decompress buffer is " + << newAvailOut << " bytes.\n" << logofs_flush; + #endif + + for (;;) + { + #ifdef INSPECT + *logofs << "\nProxyTransport: Running the decompress loop.\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_buffer_.length_ = " << r_buffer_.length_ + << ".\n" << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_buffer_.data_.size() = " << r_buffer_.data_.size() + << ".\n" << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: newAvailOut = " << newAvailOut + << ".\n" << logofs_flush; + #endif + + if (resize(r_buffer_, newAvailOut) < 0) + { + return -1; + } + + #ifdef INSPECT + *logofs << "ProxyTransport: r_buffer_.data_.size() = " + << r_buffer_.data_.size() << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_stream_.next_in = " + << (void *) r_stream_.next_in << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_stream_.avail_in = " + << r_stream_.avail_in << ".\n" + << logofs_flush; + #endif + + r_stream_.next_out = r_buffer_.data_.begin() + r_buffer_.start_ + + r_buffer_.length_; + + r_stream_.avail_out = newAvailOut; + + #ifdef INSPECT + *logofs << "ProxyTransport: r_stream_.next_out = " + << (void *) r_stream_.next_out << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_stream_.avail_out = " + << r_stream_.avail_out << ".\n" + << logofs_flush; + #endif + + int result = inflate(&r_stream_, Z_SYNC_FLUSH); + + #ifdef INSPECT + *logofs << "ProxyTransport: Called inflate() result is " + << result << ".\n" << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_stream_.avail_in = " + << r_stream_.avail_in << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_stream_.avail_out = " + << r_stream_.avail_out << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_stream_.total_in = " + << r_stream_.total_in << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_stream_.total_out = " + << r_stream_.total_out << ".\n" + << logofs_flush; + #endif + + diffTotalIn = r_stream_.total_in - oldTotalIn; + diffTotalOut = r_stream_.total_out - oldTotalOut; + + #ifdef INSPECT + *logofs << "ProxyTransport: diffTotalIn = " + << diffTotalIn << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: diffTotalOut = " + << diffTotalOut << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: r_buffer_.length_ = " + << r_buffer_.length_ << ".\n" + << logofs_flush; + #endif + + r_buffer_.length_ += diffTotalOut; + + #ifdef INSPECT + *logofs << "ProxyTransport: r_buffer_.length_ = " + << r_buffer_.length_ << ".\n" + << logofs_flush; + #endif + + oldTotalIn = r_stream_.total_in; + oldTotalOut = r_stream_.total_out; + + if (result == Z_OK) + { + if (r_stream_.avail_in == 0 && r_stream_.avail_out > 0) + { + break; + } + } + else if (result == Z_BUF_ERROR && r_stream_.avail_out > 0 && + r_stream_.avail_in == 0) + { + #ifdef TEST + *logofs << "ProxyTransport: WARNING! Raised Z_BUF_ERROR decompressing data.\n" + << logofs_flush; + #endif + + break; + } + else + { + #ifdef PANIC + *logofs << "ProxyTransport: PANIC! Decompression of data failed. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Decompression of data failed. Error is '" + << zError(result) << "'.\n"; + + finish(); + + return -1; + } + + // + // Add more bytes to the buffer. + // + + if (newAvailOut < thresholdSize_) + { + newAvailOut = thresholdSize_; + } + + #ifdef TEST + *logofs << "ProxyTransport: Need to add " << newAvailOut + << " bytes to the decompress buffer in read.\n" + << logofs_flush; + #endif + } + + diffTotalIn = r_stream_.total_in - saveTotalIn; + diffTotalOut = r_stream_.total_out - saveTotalOut; + + #ifdef DEBUG + *logofs << "ProxyTransport: Decompressed data from " + << diffTotalIn << " to " << diffTotalOut + << " bytes.\n" << logofs_flush; + #endif + + statistics -> addDecompressedBytes(diffTotalIn, diffTotalOut); + + // + // Check if the size of the buffer + // matches the produced data. + // + + if ((int) size < r_buffer_.length_) + { + #ifdef TEST + *logofs << "ProxyTransport: WARNING! Forcing a retry with " + << r_buffer_.length_ << " bytes pending and " + << size << " in the buffer.\n" + << logofs_flush; + #endif + + ESET(EAGAIN); + + return -1; + } + + // + // Copy the decompressed data to the + // provided buffer. + // + + int copied = (r_buffer_.length_ > ((int) size) ? + ((int) size) : r_buffer_.length_); + + #ifdef DEBUG + *logofs << "ProxyTransport: Going to return " << copied + << " bytes from proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + memcpy(data, r_buffer_.data_.begin() + r_buffer_.start_, copied); + + // + // Update the buffer status. + // + + r_buffer_.length_ -= copied; + + if (r_buffer_.length_ == 0) + { + r_buffer_.start_ = 0; + } + else + { + r_buffer_.start_ += copied; + + #ifdef TEST + *logofs << "ProxyTransport: There are still " << r_buffer_.length_ + << " bytes in read buffer for proxy FD#" << fd_ + << ".\n" << logofs_flush; + #endif + } + + return copied; +} + +// +// If required compress data, else write it to socket. +// + +int ProxyTransport::write(T_write type, const unsigned char *data, const unsigned int size) +{ + #ifdef TEST + if (size == 0) + { + *logofs << "ProxyTransport: WARNING! Write called for FD#" + << fd_ << " without any data to write.\n" + << logofs_flush; + + return 0; + } + #endif + + // + // If there is no compression revert to + // plain socket management. + // + + if (control -> LocalStreamCompression == 0) + { + int result = Transport::write(type, data, size); + + if (result <= 0) + { + return result; + } + + statistics -> addBytesOut(result); + + statistics -> updateBitrate(result); + + FlushCallback(result); + + return result; + } + + #ifdef DEBUG + *logofs << "ProxyTransport: Going to compress " << size + << " bytes to write buffer for proxy FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + // + // Compress data into the write buffer. + // + + int saveTotalIn = w_stream_.total_in; + int saveTotalOut = w_stream_.total_out; + + int oldTotalIn = saveTotalIn; + int oldTotalOut = saveTotalOut; + + int diffTotalIn; + int diffTotalOut; + + #ifdef INSPECT + *logofs << "ProxyTransport: oldTotalIn = " << oldTotalIn + << ".\n" << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: oldTotalOut = " << oldTotalOut + << ".\n" << logofs_flush; + #endif + + w_stream_.next_in = (Bytef *) data; + w_stream_.avail_in = size; + + // + // Let ZLIB use all the space already + // available in the buffer. + // + + unsigned int newAvailOut = w_buffer_.data_.size() - w_buffer_.start_ - + w_buffer_.length_; + + #ifdef TEST + *logofs << "ProxyTransport: Initial compress buffer is " + << newAvailOut << " bytes.\n" << logofs_flush; + #endif + + for (;;) + { + #ifdef INSPECT + *logofs << "\nProxyTransport: Running the compress loop.\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.length_ = " + << w_buffer_.length_ << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.data_.size() = " + << w_buffer_.data_.size() << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: newAvailOut = " + << newAvailOut << ".\n" + << logofs_flush; + #endif + + if (resize(w_buffer_, newAvailOut) < 0) + { + return -1; + } + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.data_.size() = " + << w_buffer_.data_.size() << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.next_in = " + << (void *) w_stream_.next_in << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.avail_in = " + << w_stream_.avail_in << ".\n" + << logofs_flush; + #endif + + w_stream_.next_out = w_buffer_.data_.begin() + w_buffer_.start_ + + w_buffer_.length_; + + w_stream_.avail_out = newAvailOut; + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.next_out = " + << (void *) w_stream_.next_out << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.avail_out = " + << w_stream_.avail_out << ".\n" + << logofs_flush; + #endif + + int result = deflate(&w_stream_, (type == write_delayed ? + Z_NO_FLUSH : Z_SYNC_FLUSH)); + + #ifdef INSPECT + *logofs << "ProxyTransport: Called deflate() result is " + << result << ".\n" << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.avail_in = " + << w_stream_.avail_in << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.avail_out = " + << w_stream_.avail_out << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.total_in = " + << w_stream_.total_in << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.total_out = " + << w_stream_.total_out << ".\n" + << logofs_flush; + #endif + + diffTotalOut = w_stream_.total_out - oldTotalOut; + diffTotalIn = w_stream_.total_in - oldTotalIn; + + #ifdef INSPECT + *logofs << "ProxyTransport: diffTotalIn = " + << diffTotalIn << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: diffTotalOut = " + << diffTotalOut << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.length_ = " + << w_buffer_.length_ << ".\n" + << logofs_flush; + #endif + + w_buffer_.length_ += diffTotalOut; + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.length_ = " + << w_buffer_.length_ << ".\n" + << logofs_flush; + #endif + + oldTotalOut = w_stream_.total_out; + oldTotalIn = w_stream_.total_in; + + if (result == Z_OK) + { + if (w_stream_.avail_in == 0 && w_stream_.avail_out > 0) + { + break; + } + } + else if (result == Z_BUF_ERROR && w_stream_.avail_out > 0 && + w_stream_.avail_in == 0) + { + #ifdef TEST + *logofs << "ProxyTransport: WARNING! Raised Z_BUF_ERROR compressing data.\n" + << logofs_flush; + #endif + + break; + } + else + { + #ifdef PANIC + *logofs << "ProxyTransport: PANIC! Compression of data failed. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Compression of data failed. Error is '" + << zError(result) << "'.\n"; + + finish(); + + return -1; + } + + // + // Add more bytes to the buffer. + // + + if (newAvailOut < thresholdSize_) + { + newAvailOut = thresholdSize_; + } + + #ifdef TEST + *logofs << "ProxyTransport: Need to add " << newAvailOut + << " bytes to the compress buffer in write.\n" + << logofs_flush; + #endif + } + + diffTotalIn = w_stream_.total_in - saveTotalIn; + diffTotalOut = w_stream_.total_out - saveTotalOut; + + #ifdef TEST + + *logofs << "ProxyTransport: Compressed data from " + << diffTotalIn << " to " << diffTotalOut + << " bytes.\n" << logofs_flush; + + if (diffTotalIn != (int) size) + { + #ifdef PANIC + *logofs << "ProxyTransport: PANIC! Bytes provided to ZLIB stream " + << "should be " << size << " but they look to be " + << diffTotalIn << ".\n" << logofs_flush; + #endif + } + + #endif + + // + // Find out what we have to do with the + // produced data. + // + + if (type == write_immediate) + { + // + // If user requested an immediate write we + // flushed the ZLIB buffer. We can now reset + // the counter and write data to socket. + // + + flush_ = 0; + + #ifdef TEST + *logofs << "ProxyTransport: Write buffer for proxy FD#" << fd_ + << " has data for " << w_buffer_.length_ << " bytes.\n" + << logofs_flush; + + *logofs << "ProxyTransport: Start is " << w_buffer_.start_ + << " length is " << w_buffer_.length_ << " flush is " + << flush_ << " size is " << w_buffer_.data_.size() + << " capacity is " << w_buffer_.data_.capacity() + << ".\n" << logofs_flush; + #endif + + // + // Alternatively may try to write only if + // the socket is not blocked. + // + // if (w_buffer_.length_ > 0 && blocked_ == 0) + // { + // ... + // } + // + + if (w_buffer_.length_ > 0) + + { + #ifdef TEST + *logofs << "ProxyTransport: Writing " << w_buffer_.length_ + << " bytes of produced data to FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + int result = Transport::flush(); + + if (result < 0) + { + return -1; + } + } + } + else + { + // + // We haven't flushed the ZLIB compression + // buffer, so user will have to call proxy + // transport's flush explicitly. + // + + flush_ += diffTotalIn; + } + + // + // We either wrote the data or added it to the + // write buffer. It's convenient to update the + // counters at this stage to get the current + // bitrate earlier. + // + + statistics -> addCompressedBytes(diffTotalIn, diffTotalOut); + + statistics -> addBytesOut(diffTotalOut); + + statistics -> updateBitrate(diffTotalOut); + + FlushCallback(diffTotalOut); + + #ifdef TEST + *logofs << "ProxyTransport: Write buffer for proxy FD#" << fd_ + << " has data for " << w_buffer_.length_ << " bytes.\n" + << logofs_flush; + + *logofs << "ProxyTransport: Start is " << w_buffer_.start_ + << " length is " << w_buffer_.length_ << " flush is " + << flush_ << " size is " << w_buffer_.data_.size() + << " capacity is " << w_buffer_.data_.capacity() + << ".\n" << logofs_flush; + #endif + + return size; +} + +// +// Write data to its file descriptor. +// + +int ProxyTransport::flush() +{ + // + // If there is no compression or we already compressed + // outgoing data and just need to write it to socket + // because of previous incomplete writes then revert + // to plain socket management. + // + + if (flush_ == 0 || control -> LocalStreamCompression == 0) + { + int result = Transport::flush(); + + if (result < 0) + { + return -1; + } + + return result; + } + + #ifdef DEBUG + *logofs << "ProxyTransport: Going to flush compression on " + << "proxy FD#" << fd_ << ".\n" << logofs_flush; + #endif + + #ifdef TEST + *logofs << "ProxyTransport: Flush counter for proxy FD#" << fd_ + << " is " << flush_ << " bytes.\n" << logofs_flush; + #endif + + // + // Flush ZLIB stream into the write buffer. + // + + int saveTotalIn = w_stream_.total_in; + int saveTotalOut = w_stream_.total_out; + + int oldTotalIn = saveTotalIn; + int oldTotalOut = saveTotalOut; + + int diffTotalOut; + int diffTotalIn; + + #ifdef INSPECT + *logofs << "ProxyTransport: oldTotalIn = " << oldTotalIn + << ".\n" << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: oldTotalOut = " << oldTotalOut + << ".\n" << logofs_flush; + #endif + + w_stream_.next_in = w_buffer_.data_.begin() + w_buffer_.start_ + w_buffer_.length_; + w_stream_.avail_in = 0; + + // + // Let ZLIB use all the space already + // available in the buffer. + // + + unsigned int newAvailOut = w_buffer_.data_.size() - w_buffer_.start_ - + w_buffer_.length_; + + #ifdef DEBUG + *logofs << "ProxyTransport: Initial flush buffer is " + << newAvailOut << " bytes.\n" << logofs_flush; + #endif + + for (;;) + { + #ifdef INSPECT + *logofs << "\nProxyTransport: Running the flush loop.\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.length_ = " + << w_buffer_.length_ << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.data_.size() = " + << w_buffer_.data_.size() << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: newAvailOut = " + << newAvailOut << ".\n" + << logofs_flush; + #endif + + if (resize(w_buffer_, newAvailOut) < 0) + { + return -1; + } + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.data_.size() = " + << w_buffer_.data_.size() << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.next_in = " + << (void *) w_stream_.next_in << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.avail_in = " + << w_stream_.avail_in << ".\n" + << logofs_flush; + #endif + + w_stream_.next_out = w_buffer_.data_.begin() + w_buffer_.start_ + + w_buffer_.length_; + + w_stream_.avail_out = newAvailOut; + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.next_out = " + << (void *) w_stream_.next_out << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.avail_out = " + << w_stream_.avail_out << ".\n" + << logofs_flush; + #endif + + int result = deflate(&w_stream_, Z_SYNC_FLUSH); + + #ifdef INSPECT + *logofs << "ProxyTransport: Called deflate() result is " + << result << ".\n" << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.avail_in = " + << w_stream_.avail_in << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.avail_out = " + << w_stream_.avail_out << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.total_in = " + << w_stream_.total_in << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_stream_.total_out = " + << w_stream_.total_out << ".\n" + << logofs_flush; + #endif + + diffTotalOut = w_stream_.total_out - oldTotalOut; + diffTotalIn = w_stream_.total_in - oldTotalIn; + + #ifdef INSPECT + *logofs << "ProxyTransport: diffTotalIn = " + << diffTotalIn << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: diffTotalOut = " + << diffTotalOut << ".\n" + << logofs_flush; + #endif + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.length_ = " + << w_buffer_.length_ << ".\n" + << logofs_flush; + #endif + + w_buffer_.length_ += diffTotalOut; + + #ifdef INSPECT + *logofs << "ProxyTransport: w_buffer_.length_ = " + << w_buffer_.length_ << ".\n" + << logofs_flush; + #endif + + oldTotalOut = w_stream_.total_out; + oldTotalIn = w_stream_.total_in; + + if (result == Z_OK) + { + if (w_stream_.avail_in == 0 && w_stream_.avail_out > 0) + { + break; + } + } + else if (result == Z_BUF_ERROR && w_stream_.avail_out > 0 && + w_stream_.avail_in == 0) + { + #ifdef TEST + *logofs << "ProxyTransport: WARNING! Raised Z_BUF_ERROR flushing data.\n" + << logofs_flush; + #endif + + break; + } + else + { + #ifdef PANIC + *logofs << "ProxyTransport: PANIC! Flush of compressed data failed. " + << "Error is '" << zError(result) << "'.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Flush of compressed data failed. Error is '" + << zError(result) << "'.\n"; + + finish(); + + return -1; + } + + // + // Add more bytes to the buffer. + // + + if (newAvailOut < thresholdSize_) + { + newAvailOut = thresholdSize_; + } + + #ifdef TEST + *logofs << "ProxyTransport: Need to add " << newAvailOut + << " bytes to the compress buffer in flush.\n" + << logofs_flush; + #endif + } + + diffTotalIn = w_stream_.total_in - saveTotalIn; + diffTotalOut = w_stream_.total_out - saveTotalOut; + + #ifdef TEST + *logofs << "ProxyTransport: Compressed flush data from " + << diffTotalIn << " to " << diffTotalOut + << " bytes.\n" << logofs_flush; + #endif + + // + // Time to move data from the write + // buffer to the real link. + // + + #ifdef DEBUG + *logofs << "ProxyTransport: Reset flush counter for proxy FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + flush_ = 0; + + #ifdef TEST + *logofs << "ProxyTransport: Write buffer for proxy FD#" << fd_ + << " has data for " << w_buffer_.length_ << " bytes.\n" + << logofs_flush; + + *logofs << "ProxyTransport: Start is " << w_buffer_.start_ + << " length is " << w_buffer_.length_ << " flush is " + << flush_ << " size is " << w_buffer_.data_.size() + << " capacity is " << w_buffer_.data_.capacity() + << ".\n" << logofs_flush; + #endif + + int result = Transport::flush(); + + if (result < 0) + { + return -1; + } + + // + // Update all the counters. + // + + statistics -> addCompressedBytes(diffTotalIn, diffTotalOut); + + statistics -> addBytesOut(diffTotalOut); + + statistics -> updateBitrate(diffTotalOut); + + FlushCallback(diffTotalOut); + + return result; +} + +unsigned int ProxyTransport::getPending(unsigned char *&data) +{ + // + // Return a pointer to the data in the + // read buffer. It is up to the caller + // to ensure that the data is consumed + // before the read buffer is reused. + // + + if (r_buffer_.length_ > 0) + { + unsigned int size = r_buffer_.length_; + + data = r_buffer_.data_.begin() + r_buffer_.start_; + + #ifdef DEBUG + *logofs << "ProxyTransport: Returning " << size + << " pending bytes from proxy FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + r_buffer_.length_ = 0; + r_buffer_.start_ = 0; + + // + // Prevent the deletion of the buffer. + // + + owner_ = 0; + + return size; + } + + #ifdef TEST + *logofs << "ProxyTransport: WARNING! No pending data " + << "for proxy FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + data = NULL; + + return 0; +} + +void ProxyTransport::fullReset() +{ + blocked_ = 0; + finish_ = 0; + flush_ = 0; + + if (control -> RemoteStreamCompression) + { + inflateReset(&r_stream_); + } + + if (control -> LocalStreamCompression) + { + deflateReset(&w_stream_); + } + + if (owner_ == 1) + { + Transport::fullReset(r_buffer_); + } + + Transport::fullReset(w_buffer_); +} + +AgentTransport::AgentTransport(int fd) : Transport(fd) +{ + #ifdef TEST + *logofs << "AgentTransport: Going to create agent transport " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + type_ = transport_agent; + + // + // Set up the read buffer. + // + + r_buffer_.length_ = 0; + r_buffer_.start_ = 0; + + r_buffer_.data_.resize(initialSize_); + + // + // For now we own the buffer. + // + + owner_ = 1; + + // + // Set up the mutexes. + // + + #ifdef THREADS + + pthread_mutexattr_t m_attributes; + + pthread_mutexattr_init(&m_attributes); + + // + // Interfaces in pthread to handle mutex + // type do not work in current version. + // + + m_attributes.__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP; + + if (pthread_mutex_init(&m_read_, &m_attributes) != 0) + { + #ifdef TEST + *logofs << "AgentTransport: Child: Creation of read mutex failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + } + + if (pthread_mutex_init(&m_write_, &m_attributes) != 0) + { + #ifdef TEST + *logofs << "AgentTransport: Child: Creation of write mutex failed. " + << "Error is " << EGET() << " '" << ESTR() + << "'.\n" << logofs_flush; + #endif + } + + #endif + + #ifdef REFERENCES + *logofs << "AgentTransport: Child: Created new object at " + << this << " out of " << ++references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +AgentTransport::~AgentTransport() +{ + #ifdef TEST + *logofs << "AgentTransport: Going to destroy derived class " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + // + // Unlock and free all mutexes. + // + + #ifdef THREADS + + pthread_mutex_unlock(&m_read_); + pthread_mutex_unlock(&m_write_); + + pthread_mutex_destroy(&m_read_); + pthread_mutex_destroy(&m_write_); + + #endif + + #ifdef REFERENCES + *logofs << "AgentTransport: Child: Deleted object at " + << this << " out of " << --references_ + << " allocated references.\n" << logofs_flush; + #endif +} + +// +// Read data enqueued by the other thread. +// + +int AgentTransport::read(unsigned char *data, unsigned int size) +{ + #ifdef THREADS + + lockRead(); + + #endif + + #ifdef DEBUG + *logofs << "AgentTransport: Child: Going to read " << size + << " bytes from " << "FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + int copied = -1; + + if (r_buffer_.length_ > 0) + { + if ((int) size < r_buffer_.length_) + { + #ifdef TEST + *logofs << "AgentTransport: WARNING! Forcing a retry with " + << r_buffer_.length_ << " bytes pending and " + << size << " in the buffer.\n" + << logofs_flush; + #endif + + ESET(EAGAIN); + } + else + { + copied = (r_buffer_.length_ > ((int) size) ? + ((int) size) : r_buffer_.length_); + + memcpy(data, r_buffer_.data_.begin() + r_buffer_.start_, copied); + + // + // Update the buffer status. + // + + #ifdef TEST + *logofs << "AgentTransport: Child: Going to immediately return " + << copied << " bytes from FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + #ifdef DUMP + + *logofs << "AgentTransport: Child: Dumping content of read data.\n" + << logofs_flush; + + DumpData(data, copied); + + #endif + + r_buffer_.length_ -= copied; + + if (r_buffer_.length_ == 0) + { + r_buffer_.start_ = 0; + } + else + { + r_buffer_.start_ += copied; + + #ifdef TEST + *logofs << "AgentTransport: Child: There are still " + << r_buffer_.length_ << " bytes in read buffer for " + << "FD#" << fd_ << ".\n" << logofs_flush; + #endif + } + } + } + else + { + #ifdef DEBUG + *logofs << "AgentTransport: Child: No data can be got " + << "from read buffer for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + ESET(EAGAIN); + } + + #ifdef THREADS + + unlockRead(); + + #endif + + return copied; +} + +// +// Write data to buffer so that the other +// thread can get it. +// + +int AgentTransport::write(T_write type, const unsigned char *data, const unsigned int size) +{ + #ifdef THREADS + + lockWrite(); + + #endif + + // + // Just append data to socket's write buffer. + // Note that we don't care if buffer exceeds + // the size limits set for this type of + // transport. + // + + #ifdef TEST + *logofs << "AgentTransport: Child: Going to append " << size + << " bytes to write buffer for " << "FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + int copied = -1; + + if (resize(w_buffer_, size) < 0) + { + finish(); + + ESET(EPIPE); + } + else + { + memmove(w_buffer_.data_.begin() + w_buffer_.start_ + w_buffer_.length_, data, size); + + w_buffer_.length_ += size; + + #ifdef DUMP + + *logofs << "AgentTransport: Child: Dumping content of written data.\n" + << logofs_flush; + + DumpData(data, size); + + #endif + + #ifdef TEST + *logofs << "AgentTransport: Child: Write buffer for FD#" << fd_ + << " has data for " << w_buffer_.length_ << " bytes.\n" + << logofs_flush; + + *logofs << "AgentTransport: Child: Start is " << w_buffer_.start_ + << " length is " << w_buffer_.length_ << " size is " + << w_buffer_.data_.size() << " capacity is " + << w_buffer_.data_.capacity() << ".\n" + << logofs_flush; + #endif + + copied = size; + } + + // + // Let child access again the read buffer. + // + + #ifdef THREADS + + unlockWrite(); + + #endif + + return copied; +} + +int AgentTransport::flush() +{ + // + // In case of memory-to-memory transport + // this function should never be called. + // + + #ifdef PANIC + *logofs << "AgentTransport: Child: PANIC! Called flush() for " + << "memory to memory transport on " << "FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Called flush() for " + << "memory to memory transport on " << "FD#" + << fd_ << ".\n"; + + HandleAbort(); +} + +int AgentTransport::drain(int limit, int timeout) +{ + // + // We can't drain the channel in the case + // of the memory-to-memory transport. Data + // is enqueued for the agent to read but + // the agent could require multiple loops + // to read it all. + // + + // + // In case of memory-to-memory transport + // this function should never be called. + // + + #ifdef PANIC + *logofs << "AgentTransport: Child: PANIC! Called drain() for " + << "memory to memory transport on " << "FD#" + << fd_ << ".\n" << logofs_flush; + #endif + + cerr << "Error" << ": Called drain() for " + << "memory to memory transport on " << "FD#" + << fd_ << ".\n"; + + HandleAbort(); +} + +unsigned int AgentTransport::getPending(unsigned char *&data) +{ + #ifdef THREADS + + lockRead(); + + #endif + + if (r_buffer_.length_ > 0) + { + unsigned int size = r_buffer_.length_; + + data = r_buffer_.data_.begin() + r_buffer_.start_; + + #ifdef DEBUG + *logofs << "AgentTransport: Child: Returning " << size + << " pending bytes from FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + r_buffer_.length_ = 0; + r_buffer_.start_ = 0; + + #ifdef THREADS + + unlockRead(); + + #endif + + // + // Prevent the deletion of the buffer. + // + + owner_ = 0; + + return size; + } + + #ifdef TEST + *logofs << "AgentTransport: WARNING! No pending data " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + #ifdef THREADS + + unlockRead(); + + #endif + + data = NULL; + + return 0; +} + +void AgentTransport::fullReset() +{ + #ifdef THREADS + + lockRead(); + lockWrite(); + + #endif + + #ifdef TEST + *logofs << "AgentTransport: Child: Resetting transport " + << "for FD#" << fd_ << ".\n" << logofs_flush; + #endif + + blocked_ = 0; + finish_ = 0; + + if (owner_ == 1) + { + Transport::fullReset(r_buffer_); + } + + Transport::fullReset(w_buffer_); +} + +int AgentTransport::enqueue(const char *data, const int size) +{ + #ifdef THREADS + + lockRead(); + + #endif + + if (finish_ == 1) + { + #if defined(PARENT) && defined(TEST) + *logofs << "AgentTransport: Parent: Returning EPIPE in " + << "write for finishing FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + ESET(EPIPE); + + return -1; + } + + // + // Always allow the agent to write + // all its data. + // + + int toPut = size; + + #if defined(PARENT) && defined(TEST) + *logofs << "AgentTransport: Parent: Going to put " << toPut + << " bytes into read buffer for FD#" << fd_ + << ". Buffer length is " << r_buffer_.length_ + << ".\n" << logofs_flush; + #endif + + if (resize(r_buffer_, toPut) < 0) + { + finish(); + + #ifdef THREADS + + unlockRead(); + + #endif + + return -1; + } + + memcpy(r_buffer_.data_.begin() + r_buffer_.start_ + r_buffer_.length_, data, toPut); + + r_buffer_.length_ += toPut; + + #if defined(DUMP) && defined(PARENT) + + *logofs << "AgentTransport: Parent: Dumping content of enqueued data.\n" + << logofs_flush; + + DumpData((const unsigned char *) data, toPut); + + #endif + + #if defined(PARENT) && defined(TEST) + *logofs << "AgentTransport: Parent: Read buffer for FD#" << fd_ + << " has now data for " << r_buffer_.length_ + << " bytes.\n" << logofs_flush; + + *logofs << "AgentTransport: Parent: Start is " << r_buffer_.start_ + << " length is " << r_buffer_.length_ << " size is " + << r_buffer_.data_.size() << " capacity is " + << r_buffer_.data_.capacity() << ".\n" + << logofs_flush; + #endif + + #ifdef THREADS + + unlockRead(); + + #endif + + return toPut; +} + +int AgentTransport::dequeue(char *data, int size) +{ + #ifdef THREADS + + lockWrite(); + + #endif + + if (w_buffer_.length_ == 0) + { + if (finish_ == 1) + { + #if defined(PARENT) && defined(TEST) + *logofs << "AgentTransport: Parent: Returning 0 in read " + << "for finishing FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + return 0; + } + + #if defined(PARENT) && defined(TEST) + *logofs << "AgentTransport: Parent: No data can be read " + << "from write buffer for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + ESET(EAGAIN); + + #ifdef THREADS + + unlockWrite(); + + #endif + + return -1; + } + + // + // Return as many bytes as possible. + // + + int toGet = ((int) size > w_buffer_.length_ ? w_buffer_.length_ : size); + + #if defined(PARENT) && defined(TEST) + *logofs << "AgentTransport: Parent: Going to get " << toGet + << " bytes from write buffer for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + memcpy(data, w_buffer_.data_.begin() + w_buffer_.start_, toGet); + + w_buffer_.start_ += toGet; + w_buffer_.length_ -= toGet; + + #if defined(DUMP) && defined(PARENT) + + *logofs << "AgentTransport: Parent: Dumping content of dequeued data.\n" + << logofs_flush; + + DumpData((const unsigned char *) data, toGet); + + #endif + + #if defined(PARENT) && defined(TEST) + *logofs << "AgentTransport: Parent: Write buffer for FD#" << fd_ + << " has now data for " << length() << " bytes.\n" + << logofs_flush; + + *logofs << "AgentTransport: Parent: Start is " << w_buffer_.start_ + << " length is " << w_buffer_.length_ << " size is " + << w_buffer_.data_.size() << " capacity is " + << w_buffer_.data_.capacity() << ".\n" + << logofs_flush; + #endif + + #ifdef THREADS + + unlockWrite(); + + #endif + + return toGet; +} + +int AgentTransport::dequeuable() +{ + if (finish_ == 1) + { + #if defined(PARENT) && defined(TEST) + *logofs << "AgentTransport: Parent: Returning EPIPE in " + << "readable for finishing FD#" << fd_ + << ".\n" << logofs_flush; + #endif + + ESET(EPIPE); + + return -1; + } + + #if defined(PARENT) && defined(TEST) + *logofs << "AgentTransport: Parent: Returning " + << w_buffer_.length_ << " as data readable " + << "from read buffer for FD#" << fd_ << ".\n" + << logofs_flush; + #endif + + return w_buffer_.length_; +} + +#ifdef THREADS + +int AgentTransport::lockRead() +{ + for (;;) + { + int result = pthread_mutex_lock(&m_read_); + + if (result == 0) + { + #ifdef DEBUG + *logofs << "AgentTransport: Read mutex locked by thread id " + << pthread_self() << ".\n" << logofs_flush; + #endif + + return 0; + } + else if (EGET() == EINTR) + { + continue; + } + else + { + #ifdef WARNING + *logofs << "AgentTransport: WARNING! Locking of read mutex by thread id " + << pthread_self() << " returned " << result << ". Error is '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + return result; + } + } +} + +int AgentTransport::lockWrite() +{ + for (;;) + { + int result = pthread_mutex_lock(&m_write_); + + if (result == 0) + { + #ifdef DEBUG + *logofs << "AgentTransport: Write mutex locked by thread id " + << pthread_self() << ".\n" << logofs_flush; + #endif + + return 0; + } + else if (EGET() == EINTR) + { + continue; + } + else + { + #ifdef WARNING + *logofs << "AgentTransport: WARNING! Locking of write mutex by thread id " + << pthread_self() << " returned " << result << ". Error is '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + return result; + } + } +} + +int AgentTransport::unlockRead() +{ + for (;;) + { + int result = pthread_mutex_unlock(&m_read_); + + if (result == 0) + { + #ifdef DEBUG + *logofs << "AgentTransport: Read mutex unlocked by thread id " + << pthread_self() << ".\n" << logofs_flush; + #endif + + return 0; + } + else if (EGET() == EINTR) + { + continue; + } + else + { + #ifdef WARNING + *logofs << "AgentTransport: WARNING! Unlocking of read mutex by thread id " + << pthread_self() << " returned " << result << ". Error is '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + return result; + } + } +} + +int AgentTransport::unlockWrite() +{ + for (;;) + { + int result = pthread_mutex_unlock(&m_write_); + + if (result == 0) + { + #ifdef DEBUG + *logofs << "AgentTransport: Write mutex unlocked by thread id " + << pthread_self() << ".\n" << logofs_flush; + #endif + + return 0; + } + else if (EGET() == EINTR) + { + continue; + } + else + { + #ifdef WARNING + *logofs << "AgentTransport: WARNING! Unlocking of write mutex by thread id " + << pthread_self() << " returned " << result << ". Error is '" + << ESTR() << "'.\n" << logofs_flush; + #endif + + return result; + } + } +} + +#endif diff --git a/nxcomp/src/Transport.h b/nxcomp/src/Transport.h new file mode 100644 index 000000000..047396af6 --- /dev/null +++ b/nxcomp/src/Transport.h @@ -0,0 +1,577 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Transport_H +#define Transport_H + +#include +#include + +#include +#include +#include + +#include "Misc.h" +#include "Control.h" + +#include "Types.h" +#include "Timestamp.h" +#include "Socket.h" + +// +// Set the verbosity level. +// + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Define this to lock and unlock the +// memory-to-memory transport buffers +// before they are accessed. The code +// is outdated and doesn't work with +// the current pthread library. +// + +#undef THREADS + +// +// Define this to know when a socket +// is created or destroyed. +// + +#undef REFERENCES + +// +// Size of buffer if not set by user. +// + +#define TRANSPORT_BUFFER_DEFAULT_SIZE 16384 + +// +// Type of transport. +// + +typedef enum +{ + transport_base, + transport_proxy, + transport_agent, + transport_last_tag + +} T_transport_type; + +// +// This class handles the buffered I/O on +// the network sockets. +// + +// +// TODO: This class is useful but adds a lot of +// overhead. There are many improvements we can +// make here: +// +// - There should be a generic Buffer class, ac- +// comodating a list of memory buffers. This +// would enable the use of the readv() and +// writev() functions to perform the I/O on +// the socket. +// +// - The buffering should be moved to the Write- +// Buffer and ReadBuffer classes. By performing +// the buffering here and there, we are dupli- +// cating a lot of code and are adding a lot +// of useless memory copies. +// +// - Stream compression should be removed. The +// proxy should compress the frames based on +// the type and should include the length of +// the decompressed data in the header of the +// packet. Besides avoiding the compression +// of packets that cannot be reduced in size, +// we would also save the additional memory +// allocations due to the fact that we don't +// know the size of the decode buffer at the +// time we read the packet from the network. +// +// - The other utilities implemented here, like +// the functions forcing a write on the socket +// or waiting for more data to become available +// should be moved to the Proxy or the Channel +// classes. +// + +class Transport +{ + public: + + // + // Member functions. + // + + Transport(int fd); + + virtual ~Transport(); + + int fd() const + { + return fd_; + } + + T_transport_type getType() + { + return type_; + } + + // + // Virtual members redefined by proxy + // and 'memory-to-memory' I/O layers. + // + + virtual int read(unsigned char *data, unsigned int size); + + virtual int write(T_write type, const unsigned char *data, const unsigned int size); + + virtual int flush(); + + virtual int drain(int limit, int timeout); + + virtual void finish() + { + fullReset(); + + finish_ = 1; + } + + virtual int length() const + { + return w_buffer_.length_; + } + + virtual int pending() const + { + return 0; + } + + virtual int readable() const + { + return GetBytesReadable(fd_); + } + + virtual int writable() const + { + return GetBytesWritable(fd_); + } + + virtual int queued() const + { + return GetBytesQueued(fd_); + } + + virtual int flushable() const + { + return 0; + } + + virtual int wait(int timeout) const; + + void setSize(unsigned int initialSize, + unsigned int thresholdSize, + unsigned int maximumSize); + + // + // Return a pointer to the data + // in the read buffer. + // + + virtual unsigned int getPending(unsigned char *&data) + { + data = NULL; + + return 0; + } + + virtual void pendingReset() + { + } + + virtual void partialReset() + { + partialReset(w_buffer_); + } + + virtual void fullReset(); + + int blocked() const + { + return blocked_; + } + + protected: + + // + // Make room in the buffer to accommodate + // at least size bytes. + // + + int resize(T_buffer &buffer, const int &size); + + void partialReset(T_buffer &buffer) + { + if (buffer.length_ == 0 && + (buffer.data_.size() > initialSize_ || + buffer.data_.capacity() > initialSize_)) + { + fullReset(buffer); + } + } + + void fullReset(T_buffer &buffer); + + // + // Data members. + // + + int fd_; + + int blocked_; + int finish_; + + T_buffer w_buffer_; + + unsigned int initialSize_; + unsigned int thresholdSize_; + unsigned int maximumSize_; + + T_transport_type type_; + + private: + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +// +// This class handles buffered I/O and +// compression of the proxy stream. +// + +class ProxyTransport : public Transport +{ + public: + + ProxyTransport(int fd); + + virtual ~ProxyTransport(); + + virtual int read(unsigned char *data, unsigned int size); + + virtual int write(T_write type, const unsigned char *data, const unsigned int size); + + virtual int flush(); + + // + // Same as in the base class. + // + // virtual int drain(int limit, int timeout); + // + // virtual void finish(); + // + + // + // Same as in the base class. + // + // virtual int length() const + // + + virtual int pending() const + { + return r_buffer_.length_; + } + + // + // Same as in the base class. + // + // virtual int readable() const; + // + // virtual int writable() const; + // + // virtual int queued() const; + // + + virtual int flushable() const + { + return flush_; + } + + // + // Same as in the base class, but + // should not be called. + // + // int drained() const; + // + // Same as in the base class. + // + // virtual int wait(int timeout) const; + // + // Same as in the base class. + // + // void setSize(unsigned int initialSize, + // unsigned int thresholdSize, + // unsigned int maximumSize); + // + + virtual unsigned int getPending(unsigned char *&data); + + virtual void pendingReset() + { + owner_ = 1; + } + + virtual void partialReset() + { + if (owner_ == 1) + { + Transport::partialReset(r_buffer_); + } + + Transport::partialReset(w_buffer_); + } + + virtual void fullReset(); + + // + // Same as in the base class. + // + // int blocked() const; + // + + protected: + + int flush_; + int owner_; + + T_buffer r_buffer_; + + z_stream r_stream_; + z_stream w_stream_; + + private: + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +// +// Handle memory-to-memory data transfers between +// an agent and the proxy. +// + +class AgentTransport : public Transport +{ + public: + + AgentTransport(int fd); + + virtual ~AgentTransport(); + + virtual int read(unsigned char *data, unsigned int size); + + virtual int write(T_write type, const unsigned char *data, const unsigned int size); + + // + // These two should never be called. + // + + virtual int flush(); + + virtual int drain(int limit, int timeout); + + // + // Same as in the base class. + // + // virtual void finish(); + // + + // + // Same as in the base class. + // + // virtual int length() const + // + + virtual int pending() const + { + return r_buffer_.length_; + } + + // + // These are intended to operate only + // on the internal buffers. + // + + virtual int readable() const + { + return r_buffer_.length_; + } + + virtual int writable() const + { + return control -> TransportMaximumBufferSize; + } + + virtual int queued() const + { + return 0; + } + + // + // Same as in the base class. + // + // virtual int flushable() const; + // + // Same as in the base class, but + // should not be called. + // + // int drained() const; + // + + // + // Return immediately or will + // block until the timeout. + // + + virtual int wait(int timeout) const + { + return 0; + } + + // + // Same as in the base class. + // + // void setSize(unsigned int initialSize, + // unsigned int thresholdSize, + // unsigned int maximumSize); + // + + virtual unsigned int getPending(unsigned char *&data); + + virtual void pendingReset() + { + owner_ = 1; + } + + virtual void partialReset() + { + if (owner_ == 1) + { + Transport::partialReset(r_buffer_); + } + + Transport::partialReset(w_buffer_); + } + + virtual void fullReset(); + + // + // Same as in the base class. + // + // int blocked() const; + // + + // + // The following are specific of the + // memory-to-memory transport. + // + + int enqueue(const char *data, const int size); + + int dequeue(char *data, int size); + + int queuable() + { + // + // Always allow the agent to enqueue + // more data. + // + + return control -> TransportMaximumBufferSize; + } + + int dequeuable(); + + protected: + + // + // Lock the buffer to handle reads and + // writes safely. + // + + #ifdef THREADS + + int lockRead(); + int lockWrite(); + + int unlockRead(); + int unlockWrite(); + + #endif + + // + // Data members. + // + + int owner_; + + T_buffer r_buffer_; + + // + // Mutexes for safe read and write. + // + + #ifdef THREADS + + pthread_mutex_t m_read_; + pthread_mutex_t m_write_; + + #endif + + private: + + #ifdef REFERENCES + + static int references_; + + #endif +}; + +#endif /* Transport_H */ diff --git a/nxcomp/src/Types.h b/nxcomp/src/Types.h new file mode 100644 index 000000000..e82664c81 --- /dev/null +++ b/nxcomp/src/Types.h @@ -0,0 +1,271 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Types_H +#define Types_H + +using namespace std; + +#include +#include +#include +#include + +#include "MD5.h" + +// +// This is MD5 length. +// + +#define MD5_LENGTH 16 + +// +// Types of repositories. Replace the original +// clear() methods from STL in order to actually +// free the unused memory. +// + +class Message; + +class T_data : public vector < unsigned char > +{ + public: + + unsigned char *begin() + { + return &*(vector < unsigned char >::begin()); + } + + const unsigned char *begin() const + { + return &*(vector < unsigned char >::begin()); + } + + // Avoid overriding clear() when using libc++. Fiddling with STL internals + // doesn't really seem like a good idea to me anyway. + #ifndef _LIBCPP_VECTOR + void clear() + { + #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) + + #if defined(__GLIBCPP_INTERNAL_VECTOR_H) + + _Destroy(_M_start, _M_finish); + + #else /* #if defined(__GLIBCPP_INTERNAL_VECTOR_H) */ + + destroy(_M_start, _M_finish); + + #endif /* #if defined(__GLIBCPP_INTERNAL_VECTOR_H) */ + + _M_deallocate(_M_start, _M_end_of_storage - _M_start); + + _M_start = _M_finish = _M_end_of_storage = 0; + + #else /* #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) */ + + #if defined(_GLIBCXX_VECTOR) + + _Destroy(this->_M_impl._M_start, this->_M_impl._M_finish); + + _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage - this->_M_impl._M_start); + + this->_M_impl._M_start = this->_M_impl._M_finish = this->_M_impl._M_end_of_storage = 0; + + #else /* #if defined(_GLIBCXX_VECTOR) */ + + destroy(start, finish); + + deallocate(); + + start = finish = end_of_storage = 0; + + #endif /* #if defined(_GLIBCXX_VECTOR) */ + + #endif /* #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) */ + } + #endif /* #ifdef _LIBCPP_VECTOR */ +}; + +class T_messages : public vector < Message * > +{ + public: + + // Avoid overriding clear() when using libc++. Fiddling with STL internals + // doesn't really seem like a good idea to me anyway. + #ifndef _LIBCPP_VECTOR + void clear() + { + #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) + + #if defined(__GLIBCPP_INTERNAL_VECTOR_H) + + _Destroy(_M_start, _M_finish); + + #else /* #if defined(__GLIBCPP_INTERNAL_VECTOR_H) */ + + destroy(_M_start, _M_finish); + + #endif /* #if defined(__GLIBCPP_INTERNAL_VECTOR_H) */ + + _M_deallocate(_M_start, _M_end_of_storage - _M_start); + + _M_start = _M_finish = _M_end_of_storage = 0; + + #else /* #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) */ + + #if defined(_GLIBCXX_VECTOR) + + _Destroy(this->_M_impl._M_start, this->_M_impl._M_finish); + + _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage - this->_M_impl._M_start); + + this->_M_impl._M_start = this->_M_impl._M_finish = this->_M_impl._M_end_of_storage = 0; + + #else /* #if defined(_GLIBCXX_VECTOR) */ + + destroy(start, finish); + + deallocate(); + + start = finish = end_of_storage = 0; + + #endif /* #if defined(_GLIBCXX_VECTOR) */ + + #endif /* #if defined(__STL_USE_STD_ALLOCATORS) || defined(__GLIBCPP_INTERNAL_VECTOR_H) */ + } + #endif /* #ifndef _LIBCPP_VECTOR */ +}; + +typedef md5_byte_t * T_checksum; + +struct T_less +{ + bool operator()(T_checksum a, T_checksum b) const + { + return (memcmp(a, b, MD5_LENGTH) < 0); + } +}; + +typedef map < T_checksum, int, T_less > T_checksums; + +class Split; + +typedef list < Split * > T_splits; + +class File; + +struct T_older +{ + bool operator()(File *a, File *b) const; +}; + +typedef set < File *, T_older > T_files; + +typedef list < int > T_list; + +// +// Used to accommodate data to be read and +// written to a socket. +// + +typedef struct +{ + T_data data_; + int length_; + int start_; +} +T_buffer; + +// +// The message store operation that was +// executed for the message. The channels +// use these values to determine how to +// handle the message after it has been +// received at the decoding side. +// + +// Since ProtoStep8 (#issue 108) +enum T_store_action +{ + is_hit, + is_added, + is_discarded, + is_removed +}; + +// Since ProtoStep8 (#issue 108) +#define IS_HIT is_hit +#define IS_ADDED is_added + +enum T_checksum_action +{ + use_checksum, + discard_checksum +}; + +enum T_data_action +{ + use_data, + discard_data +}; + +// +// Message is going to be weighted for +// deletion at insert or cleanup time? +// + +enum T_rating +{ + rating_for_insert, + rating_for_clean +}; + +// +// How to handle the writes to the X +// and proxy connections. +// + +enum T_write +{ + write_immediate, + write_delayed +}; + +enum T_flush +{ + flush_if_needed, + flush_if_any +}; + +// +// This is the value to indicate an +// invalid position in the message +// store. +// + +static const int nothing = -1; + +#endif /* Types_H */ diff --git a/nxcomp/src/Unpack.cpp b/nxcomp/src/Unpack.cpp new file mode 100644 index 000000000..e63e836f0 --- /dev/null +++ b/nxcomp/src/Unpack.cpp @@ -0,0 +1,1514 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Misc.h" +#include "Unpack.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +// +// Used for the ZLIB decompression +// of RGB, alpha and colormap data. +// + +z_stream unpackStream; + +static int unpackInitialized; + +int Unpack8To8(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack8To8(T_colormap *colormap, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack8To16(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack8To16(T_colormap *colormap, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack8To24(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack8To24(T_colormap *colormap, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack8To32(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack8To32(T_colormap *colormap, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack15To16(const unsigned char *data, unsigned char *out, + unsigned char *end); + +int Unpack15To24(const unsigned char *data, unsigned char *out, + unsigned char *end); + +int Unpack15To32(const unsigned char *data, unsigned char *out, + unsigned char *end); + +int Unpack16To16(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack16To16(const unsigned char *data, unsigned char *out, + unsigned char *end, int imageByteOrder); + +int Unpack16To24(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack16To24(const unsigned char *data, unsigned char *out, + unsigned char *end, int imageByteOrder); + +int Unpack16To32(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack16To32(const unsigned char *data, unsigned char *out, + unsigned char *end, int imageByteOrder); + +int Unpack24To24(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack24To24(const unsigned char *data, unsigned char *out, + unsigned char *end); + +int Unpack24To32(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + +int Unpack24To32(const unsigned char *data, unsigned char *out, unsigned char *end); + +int Unpack32To32(const T_colormask *colormask, const unsigned int *data, + unsigned int *out, unsigned int *end); + + +void UnpackInit() +{ + if (unpackInitialized == 0) + { + unpackStream.zalloc = (alloc_func) 0; + unpackStream.zfree = (free_func) 0; + unpackStream.opaque = (voidpf) 0; + + unpackStream.next_in = (Bytef *) 0; + unpackStream.avail_in = 0; + + int result = inflateInit2(&unpackStream, 15); + + if (result != Z_OK) + { + #ifdef PANIC + *logofs << "UnpackInit: PANIC! Cannot initialize the Z stream " + << "for decompression. Error is '" << zError(result) + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Cannot initialize the Z stream for " + << "decompression. Error is '" << zError(result) + << "'.\n"; + } + else + { + unpackInitialized = 1; + } + } +} + +void UnpackDestroy() +{ + if (unpackInitialized == 1) + { + inflateEnd(&unpackStream); + + unpackInitialized = 0; + } +} + +// +// Get bits per pixel set by client +// according to display geometry. +// + +int UnpackBitsPerPixel(T_geometry *geometry, unsigned int depth) +{ + switch (depth) + { + case 1: + { + return geometry -> depth1_bpp; + } + case 4: + { + return geometry -> depth4_bpp; + } + case 8: + { + return geometry -> depth8_bpp; + } + case 15: + case 16: + { + return geometry -> depth16_bpp; + } + case 24: + { + return geometry -> depth24_bpp; + } + case 32: + { + return geometry -> depth32_bpp; + } + default: + { + return 0; + } + } +} + +int Unpack8To8(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack8To8: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + memcpy(out, data, end - out); + + return 1; +} + +int Unpack8To16(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack8To16: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + unsigned short *out16 = (unsigned short *) out; + unsigned short *end16 = (unsigned short *) end; + + while (out16 < end16) + { + if (*data == 0) + { + *out16 = 0x0; + } + else if (*data == 0xff) + { + *out16 = 0xffff; + } + else + { + // + // Pixel layout: + // + // 8bits 00RRGGBB -> 16bits RR000GG0 000BB000. + // + + *out16 = (((((*data & 0x30) << 2) | colormask -> correction_mask) << 8) & 0xf800) | + (((((*data & 0xc) << 4) | colormask -> correction_mask) << 3) & 0x7e0) | + (((((*data & 0x3) << 6) | colormask -> correction_mask) >> 3) & 0x1f); + } + + out16++; + data++; + } + + return 1; +} + +int Unpack8To24(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack8To24: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + while (out < (end - 2)) + { + if (*data == 0x00) + { + out[0] = out[1] = out[2] = 0x00; + } + else if (*data == 0xff) + { + out[0] = out[1] = out[2] = 0xff; + } + else + { + // + // Pixel layout: + // + // 8bits 00RRGGBB -> 24bits RR000000 GG00000 BB000000. + // + + out[0] = (((*data & 0x30) << 2) | colormask -> correction_mask); + out[1] = (((*data & 0x0c) << 4) | colormask -> correction_mask); + out[2] = (((*data & 0x03) << 6) | colormask -> correction_mask); + } + + out += 3; + data += 1; + } + + return 1; +} + +int Unpack8To32(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack8To32: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + unsigned int *out32 = (unsigned int *) out; + unsigned int *end32 = (unsigned int *) end; + + while (out32 < end32) + { + if (*data == 0) + { + *out32 = 0x0; + } + else if (*data == 0xff) + { + *out32 = 0xffffff; + } + else + { + *out32 = ((((*data & 0x30) << 2) | colormask -> correction_mask) << 16) | + ((((*data & 0xc) << 4) | colormask -> correction_mask) << 8) | + (((*data & 0x3) << 6) | colormask -> correction_mask); + } + + out32++; + data++; + } + + return 1; +} + +int Unpack8(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size) +{ + int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); + + int (*unpack)(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + + switch (dst_bpp) + { + case 8: + { + unpack = Unpack8To8; + + break; + } + case 16: + { + unpack = Unpack8To16; + + break; + } + case 24: + { + unpack = Unpack8To24; + + break; + } + case 32: + { + unpack = Unpack8To32; + + break; + } + default: + { + #ifdef PANIC + *logofs << "Unpack8: PANIC! Bad destination bits per pixel " + << dst_bpp << ". Only 16/24/32 are supported.\n" + << logofs_flush; + #endif + + return -1; + } + } + + if (dst_bpp == 24) + { + unsigned char *dst_end = dst_data; + + #ifdef TEST + *logofs << "Unpack8: Handling 24 bits with dst_size " + << dst_size << ".\n" << logofs_flush; + #endif + + for (int y = 0; y < dst_height; y++) + { + dst_data = dst_end; + + dst_end += RoundUp4(dst_width * 3); + + (*unpack)(colormask, src_data, dst_data, dst_end); + + src_data += src_width; + } + } + else + { + unsigned char *dst_end = dst_data + dst_size; + + (*unpack)(colormask, src_data, dst_data, dst_end); + } + + return 1; +} + +int Unpack16To16(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack16To16: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + if (colormask -> correction_mask) + { + unsigned short *data16 = (unsigned short *) data; + + unsigned short *out16 = (unsigned short *) out; + unsigned short *end16 = (unsigned short *) end; + + while (out16 < end16) + { + if (*data16 == 0x0000) + { + *out16 = 0x0000; + } + else if (*data16 == 0xffff) + { + *out16 = 0xffff; + } + else + { + // + // Pixel layout: + // + // 16bit RRRRRGGG GG0BBBBB -> RRRRRGGG GGGBBBBB. + // + + *out16 = (((((*data16 & 0xf100) >> 8) | colormask -> correction_mask) << 8) & 0xf800) | + (((((*data16 & 0x7c0) >> 3) | colormask -> correction_mask) << 3) & 0x7e0) | + (((((*data16 & 0x1f) << 3) | colormask -> correction_mask) >> 3) & 0x1f); + } + + out16++; + data16++; + } + } + else + { + #ifdef TEST + *logofs << "Unpack16To16: Using bitwise copy due to null correction mask.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) out, (unsigned char *) data, end - out); + } + + return 1; +} + +int Unpack16To24(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack16To24: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + unsigned short *data16 = (unsigned short *) data; + + + while (out < end - 2) + { + if (*data16 == 0x0) + { + out[0] = 0x00; + out[1] = 0x00; + out[2] = 0x00; + } + else if (*data16 == 0xffff) + { + out[0] = 0xff; + out[1] = 0xff; + out[2] = 0xff; + } + else + { + #ifdef TEST + *logofs << "Unpack16To24: Pixel [" << *data16 << "]\n" + << logofs_flush; + #endif + + // + // Pixel layout: + // + // 16bit 0RRRRRGG GGGBBBBB -> 24 bit RRRRR000 GGGGG000 BBBBB000 + // + + out[0] = (((*data16 & 0x7c00) >> 7) | colormask -> correction_mask); + out[1] = (((*data16 & 0x03e0) >> 2) | colormask -> correction_mask); + out[2] = (((*data16 & 0x001f) << 3) | colormask -> correction_mask); + } + + out += 3; + data16 += 1; + } + + return 1; +} + +int Unpack16To32(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack16To32: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + unsigned short *data16 = (unsigned short *) data; + + unsigned int *out32 = (unsigned int *) out; + unsigned int *end32 = (unsigned int *) end; + + while (out32 < end32) + { + if (*data16 == 0x0) + { + *out32 = 0x0; + } + else if (*data16 == 0xffff) + { + *out32 = 0xffffff; + } + else + { + *out32 = ((((*data16 & 0x7c00) >> 7) | colormask -> correction_mask) << 16) | + ((((*data16 & 0x3e0) >> 2) | colormask -> correction_mask) << 8) | + (((*data16 & 0x1f) << 3) | colormask -> correction_mask); + } + + out32++; + data16++; + } + + return 1; +} + +int Unpack16(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size) +{ + int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); + + int (*unpack)(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + + switch (dst_bpp) + { + case 16: + { + unpack = Unpack16To16; + + break; + } + case 24: + { + unpack = Unpack16To24; + + break; + } + case 32: + { + unpack = Unpack16To32; + + break; + } + default: + { + #ifdef PANIC + *logofs << "Unpack16: PANIC! Bad destination bits per pixel " + << dst_bpp << ". Only 24/32 are supported.\n" + << logofs_flush; + #endif + + return -1; + } + } + + if (dst_bpp == 24) + { + unsigned char *dst_end = dst_data; + + for (int y = 0; y < dst_height; y++) + { + dst_data = dst_end; + + dst_end += RoundUp4(dst_width * 3); + + (*unpack)(colormask, src_data, dst_data, dst_end); + + src_data += (src_width * 2); + } + + } + else + { + unsigned char *dst_end = dst_data + dst_size; + + (*unpack)(colormask, src_data, dst_data, dst_end); + } + + return 1; +} + +int Unpack24To24(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack24To24: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + if (colormask -> correction_mask) + { + while (out < end) + { + if (data[0] == 0x00 && + data[1] == 0x00 && + data[2] == 0x00) + { + out[0] = out[1] = out[2] = 0x00; + } + else if (data[0] == 0xff && + data[1] == 0xff && + data[2] == 0xff) + { + out[0] = out[1] = out[2] = 0xff; + } + else + { + out[0] = (data[0] | colormask -> correction_mask); + out[1] = (data[1] | colormask -> correction_mask); + out[2] = (data[2] | colormask -> correction_mask); + } + + out += 3; + data += 3; + } + } + else + { + #ifdef TEST + *logofs << "Unpack24To24: Using bitwise copy due to null correction mask.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) out, (unsigned char *) data, end - out); + } + + return 1; +} + +int Unpack24To32(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack24To32: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + unsigned int *out32 = (unsigned int *) out; + unsigned int *end32 = (unsigned int *) end; + + while (out32 < end32) + { + if (colormask -> color_mask == 0xff) + { + *out32 = (data[0] << 16) | (data[1] << 8) | data[2]; + } + else + { + if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x0) + { + *out32 = 0x0; + } + else if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) + { + *out32 = 0xffffff; + } + else + { + *out32 = (((unsigned int) data[0] | colormask -> correction_mask) << 16) | + (((unsigned int) data[1] | colormask -> correction_mask) << 8) | + ((unsigned int) data[2] | colormask -> correction_mask); + } + } + + out32 += 1; + data += 3; + } + + return 1; +} + +int Unpack24(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size) +{ + int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); + + int (*unpack)(const T_colormask *colormask, const unsigned char *data, + unsigned char *out, unsigned char *end); + + switch (dst_bpp) + { + case 24: + { + unpack = Unpack24To24; + + break; + } + case 32: + { + unpack = Unpack24To32; + + break; + } + default: + { + #ifdef PANIC + *logofs << "Unpack24: PANIC! Bad destination bits per pixel " + << dst_bpp << ". Only 32 is supported.\n" + << logofs_flush; + #endif + + return -1; + } + } + + if (dst_bpp == 24) + { + unsigned char *dst_end; + unsigned long scanline_size = RoundUp4(dst_width * dst_bpp / 8); + + dst_end = dst_data; + + #ifdef TEST + *logofs << "Unpack24: Handling 24 bits with dst_height " + << dst_height << " scanline_size " << scanline_size + << " dst_size " << dst_size << ".\n" << logofs_flush; + #endif + + for (int y = 0; y < dst_height; y++) + { + dst_data = dst_end; + + dst_end += scanline_size; + + (*unpack)(colormask, src_data, dst_data, dst_end); + + src_data += scanline_size; + } + } + else + { + unsigned char *dst_end = dst_data + dst_size; + + (*unpack)(colormask, src_data, dst_data, dst_end); + } + + return 1; +} + +int Unpack8To8(T_colormap *colormap, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack8To8: Unpacking " << end - out + << " bytes of colormapped data.\n" + << logofs_flush; + #endif + + while (out < end) + { + *(out++) = (unsigned char) colormap -> data[*(data++)]; + } + + return 1; +} + +int Unpack8To16(T_colormap *colormap, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack8To16: Unpacking " << end - out + << " bytes of colormapped data.\n" + << logofs_flush; + #endif + + unsigned short *out16 = (unsigned short *) out; + unsigned short *end16 = (unsigned short *) end; + + while (out16 < end16) + { + *(out16++) = (unsigned short) colormap -> data[*(data++)]; + } + + return 1; +} + +int Unpack8To24(T_colormap *colormap, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack8To24: Unpacking " << end - out + << " bytes of colormapped data.\n" + << logofs_flush; + #endif + + unsigned int value; + + while (out < end) + { + value = colormap -> data[*(data++)]; + + *(out++) = value; + *(out++) = value >> 8; + *(out++) = value >> 16; + } + + return 1; +} + +int Unpack8To32(T_colormap *colormap, const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack8To32: Unpacking " << end - out + << " bytes of colormapped data.\n" + << logofs_flush; + #endif + + unsigned int *out32 = (unsigned int *) out; + unsigned int *end32 = (unsigned int *) end; + + while (out32 < end32) + { + *(out32++) = colormap -> data[*(data++)]; + } + + return 1; +} + +int Unpack8(T_geometry *geometry, T_colormap *colormap, int src_depth, int src_width, int src_height, + unsigned char *src_data, int src_size, int dst_depth, int dst_width, + int dst_height, unsigned char *dst_data, int dst_size) +{ + if (src_depth != 8) + { + #ifdef PANIC + *logofs << "Unpack8: PANIC! Cannot unpack colormapped image of source depth " + << src_depth << ".\n" << logofs_flush; + #endif + + return -1; + } + + int (*unpack)(T_colormap *colormap, const unsigned char *data, + unsigned char *out, unsigned char *end); + + int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); + + switch (dst_bpp) + { + case 8: + { + unpack = Unpack8To8; + + break; + } + case 16: + { + unpack = Unpack8To16; + + break; + } + case 24: + { + unpack = Unpack8To24; + + break; + } + case 32: + { + unpack = Unpack8To32; + + break; + } + default: + { + #ifdef PANIC + *logofs << "Unpack8: PANIC! Bad destination bits per pixel " + << dst_bpp << ". Only 8/16/24/32 are supported.\n" + << logofs_flush; + #endif + + return -1; + } + } + + if (src_width == dst_width && + src_height == dst_height) + { + unsigned char *dst_end = dst_data + dst_size; + + (*unpack)(colormap, src_data, dst_data, dst_end); + } + else if (src_width >= dst_width && + src_height >= dst_height) + { + unsigned char *dst_end = dst_data; + + for (int y = 0; y < dst_height; y++) + { + dst_data = dst_end; + + dst_end += RoundUp4(dst_width * dst_bpp / 8); + + (*unpack)(colormap, src_data, dst_data, dst_end); + + src_data += src_width; + } + } + else + { + #ifdef PANIC + *logofs << "Unpack8: PANIC! Cannot unpack image. " + << "Destination area " << dst_width << "x" + << dst_height << " is not fully contained in " + << src_width << "x" << src_height << " source.\n" + << logofs_flush; + #endif + + return -1; + } + + return 1; +} + +int Unpack15To16(const unsigned char *data, unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack15To16: Unpacking " << end - out + << " bytes of colormapped data.\n" + << logofs_flush; + #endif + + unsigned short *data16 = (unsigned short *) data; + unsigned short *out16 = (unsigned short *) out; + unsigned short *end16 = (unsigned short *) end; + + while (out16 < end16) + { + if (*data16 == 0x0) + { + *out16 = 0x0; + } + else if (*data16 == 0x7fff) + { + *out16 = 0xffff; + } + else + { + #ifdef TEST + *logofs << "Unpack15To16: Pixel [" << *data16 << "]\n" + << logofs_flush; + #endif + + *out16 = ((*data16 & 0x7ff0) << 1) | + (*data16 & 0x001f); + } + + out16 += 1; + data16 += 1; + } + + return 1; +} + +int Unpack15To24(const unsigned char *data, unsigned char *out, unsigned char *end) + +{ + #ifdef TEST + *logofs << "Unpack15To24: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + unsigned short *data16 = (unsigned short *) data; + + while (out < end - 2) + { + if (*data16 == 0x0) + { + out[0] = 0x00; + out[1] = 0x00; + out[2] = 0x00; + } + else if (*data16 == 0x7fff) + { + out[0] = 0xff; + out[1] = 0xff; + out[2] = 0xff; + } + else + { + #ifdef TEST + *logofs << "Unpack15To24: Pixel [" << *data16 << "]\n" + << logofs_flush; + #endif + + out[0] = ((*data16 >> 7) & 0xf8) | ((*data16 >> 12) & 0x07); + out[1] = ((*data16 >> 2) & 0xf8) | ((*data16 >> 8) & 0x07); + out[2] = ((*data16 << 3) & 0xf8) | ((*data16 >> 2) & 0x07); + } + + out += 3; + data16 += 1; + } + + return 1; +} + +int Unpack15To32(const unsigned char *data, unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack15To32: Unpacking " << end - out + << " bytes of data.\n" + << logofs_flush; + #endif + + unsigned short *data16 = (unsigned short *) data; + unsigned int *out32 = (unsigned int *) out; + unsigned int *end32 = (unsigned int *) end; + + while (out32 < end32) + { + if (*data16 == 0x0) + { + *out32 = 0x0; + } + else if (*data16 == 0xffff) + { + *out32 = 0xffffff; + } + else + { + *out32 = ((((*data16 >> 7) & 0xf8) | ((*data16 >> 12) & 0x07)) << 16) | + ((((*data16 >> 2) & 0xf8) | ((*data16 >> 8) & 0x07)) << 8) | + (((*data16 << 3) & 0xf8) | ((*data16 >> 2) & 0x07)); + } + + out32++; + data16++; + } + + return 1; +} + +int Unpack15(T_geometry *geometry, int src_depth, int src_width, int src_height, + unsigned char *src_data, int src_size, int dst_depth, int dst_width, + int dst_height, unsigned char *dst_data, int dst_size) +{ + if (src_depth != 16) + { + #ifdef PANIC + *logofs << "Unpack15: PANIC! Cannot unpack colormapped image of source depth " + << src_depth << ".\n" << logofs_flush; + #endif + + return -1; + } + + int (*unpack)(const unsigned char *data, unsigned char *out, unsigned char *end); + + int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); + + switch (dst_bpp) + { + case 16: + { + unpack = Unpack15To16; + + break; + } + case 24: + { + unpack = Unpack15To24; + + break; + } + case 32: + { + unpack = Unpack15To32; + + break; + } + default: + { + #ifdef PANIC + *logofs << "Unpack15: PANIC! Bad destination bits per pixel " + << dst_bpp << ". Only 16/24/32 are supported.\n" + << logofs_flush; + #endif + + return -1; + } + } + + if (src_width == dst_width && src_height == dst_height) + { + unsigned char *dst_end = dst_data + dst_size; + + (*unpack)(src_data, dst_data, dst_end); + } + else if (src_width >= dst_width && src_height >= dst_height) + { + unsigned char *dst_end = dst_data; + + for (int y = 0; y < dst_height; y++) + { + dst_data = dst_end; + dst_end += RoundUp4(dst_width * dst_bpp / 8); + + (*unpack)(src_data, dst_data, dst_end); + + src_data += src_width * 2; + } + } + else + { + #ifdef PANIC + *logofs << "Unpack15: PANIC! Cannot unpack image. " + << "Destination area " << dst_width << "x" + << dst_height << " is not fully contained in " + << src_width << "x" << src_height << " source.\n" + << logofs_flush; + #endif + + return -1; + } + + return 1; +} + +int Unpack16To16(const unsigned char *data, unsigned char *out, + unsigned char *end, int imageByteOrder) +{ + #ifdef TEST + *logofs << "Unpack16To16: Unpacking " << end - out + << " bytes of colormapped data.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) out, (unsigned char *) data, end - out); + + return 1; +} + +int Unpack16To24(const unsigned char *data, unsigned char *out, + unsigned char *end, int imageByteOrder) + +{ + #ifdef TEST + *logofs << "Unpack16To24: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + unsigned short *data16 = (unsigned short *) data; + + while (out < end - 2) + { + if (*data16 == 0x0) + { + out[0] = 0x00; + out[1] = 0x00; + out[2] = 0x00; + } + else if (*data16 == 0xffff) + { + out[0] = 0xff; + out[1] = 0xff; + out[2] = 0xff; + } + else + { + #ifdef TEST + *logofs << "Unpack16To24: Pixel [" << *data16 << "]\n" + << logofs_flush; + #endif + + out[0] = ((*data16 >> 8) & 0xf8) | ((*data16 >> 13) & 0x07); + out[1] = ((*data16 >> 3) & 0xfc) | ((*data16 >> 9) & 0x03); + out[2] = ((*data16 << 3) & 0xf8) | ((*data16 >> 2) & 0x07); + } + + out += 3; + data16 += 1; + } + + return 1; +} + + +int Unpack16To32(const unsigned char *data, unsigned char *out, + unsigned char *end, int imageByteOrder) +{ + #ifdef TEST + *logofs << "Unpack16To32: Unpacking " << end - out + << " bytes of data.\n" + << logofs_flush; + #endif + + unsigned short *data16 = (unsigned short *) data; + unsigned int *out32 = (unsigned int *) out; + unsigned int *end32 = (unsigned int *) end; + + unsigned short pixel16; + unsigned int pixel32; + + while (out32 < end32) + { + + pixel16 = GetUINT((unsigned char *)data16, 0); + + if (pixel16 == 0x0) + { + PutULONG(0x0, (unsigned char *) out32, imageByteOrder); + } + else if (pixel16 == 0xffff) + { + PutULONG(0xffffff, (unsigned char *) out32, imageByteOrder); + } + else + { + pixel32 = ((((pixel16 >> 8) & 0xf8) | ((pixel16 >> 13) & 0x07)) << 16) | + ((((pixel16 >> 3) & 0xfc) | ((pixel16 >> 9) & 0x03)) << 8) | + (((pixel16 << 3) & 0xf8) | ((pixel16 >> 2) & 0x07)); + + PutULONG(pixel32, (unsigned char *) out32, imageByteOrder); + } + + out32++; + data16++; + } + return 1; +} + +int Unpack16(T_geometry *geometry, int src_depth, int src_width, int src_height, + unsigned char *src_data, int src_size, int dst_depth, int dst_width, + int dst_height, unsigned char *dst_data, int dst_size) +{ + int imageByteOrder = geometry -> image_byte_order; + + if (src_depth != 16) + { + #ifdef PANIC + *logofs << "Unpack16: PANIC! Cannot unpack colormapped image of source depth " + << src_depth << ".\n" << logofs_flush; + #endif + + return -1; + } + + int (*unpack)(const unsigned char *data, unsigned char *out, + unsigned char *end, int imageByteOrder); + + int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); + + switch (dst_bpp) + { + case 16: + { + unpack = Unpack16To16; + + break; + } + case 24: + { + unpack = Unpack16To24; + + break; + } + case 32: + { + unpack = Unpack16To32; + + break; + } + default: + { + #ifdef PANIC + *logofs << "Unpack16: PANIC! Bad destination bits per pixel " + << dst_bpp << ". Only 16/24/32 are supported.\n" + << logofs_flush; + #endif + + return -1; + } + } + + if (src_width == dst_width && src_height == dst_height) + { + unsigned char *dst_end = dst_data + dst_size; + + (*unpack)(src_data, dst_data, dst_end, imageByteOrder); + } + else if (src_width >= dst_width && src_height >= dst_height) + { + unsigned char *dst_end = dst_data; + + for (int y = 0; y < dst_height; y++) + { + dst_data = dst_end; + dst_end += RoundUp4(dst_width * dst_bpp / 8); + + (*unpack)(src_data, dst_data, dst_end, imageByteOrder); + + src_data += src_width * 2; + } + } + else + { + #ifdef PANIC + *logofs << "Unpack16: PANIC! Cannot unpack image. " + << "Destination area " << dst_width << "x" + << dst_height << " is not fully contained in " + << src_width << "x" << src_height << " source.\n" + << logofs_flush; + #endif + + return -1; + } + + return 1; +} + +int Unpack24To24(const unsigned char *data, + unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack124To24: Unpacking " << end - out + << " bytes of colormapped data.\n" + << logofs_flush; + #endif + + while (out < end) + { + *(out++) = *(data++); + } + + return 1; +} + +int Unpack24To32(const unsigned char *data, unsigned char *out, unsigned char *end) +{ + #ifdef TEST + *logofs << "Unpack24To32: Unpacking " << end - out + << " bytes of colormapped data.\n" + << logofs_flush; + #endif + + unsigned int *out32 = (unsigned int *) out; + unsigned int *end32 = (unsigned int *) end; + + while (out32 < end32) + { + if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x0) + { + *out32 = 0x0; + } + else if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) + { + *out32 = 0xffffff; + } + else + { + *out32 = (data[2] << 16) | (data[1] << 8) | data[0]; + } + + out32 += 1; + data += 3; + } + + return 1; +} + +int Unpack24(T_geometry *geometry, int src_depth, int src_width, int src_height, + unsigned char *src_data, int src_size, int dst_depth, int dst_width, + int dst_height, unsigned char *dst_data, int dst_size) + +{ + if (src_depth != 24) + { + #ifdef PANIC + *logofs << "Unpack24: PANIC! Cannot unpack colormapped image of source depth " + << src_depth << ".\n" << logofs_flush; + #endif + + return -1; + } + + int (*unpack)(const unsigned char *data, unsigned char *out, unsigned char *end); + + int dst_bpp = UnpackBitsPerPixel(geometry, dst_depth); + + switch (dst_bpp) + { + case 24: + { + unpack = Unpack24To24; + + break; + } + case 32: + { + unpack = Unpack24To32; + + break; + } + default: + { + #ifdef PANIC + *logofs << "Unpack24: PANIC! Bad destination bits per pixel " + << dst_bpp << ". Only 24/32 are supported.\n" + << logofs_flush; + #endif + + return -1; + } + } + + if (src_width == dst_width && src_height == dst_height) + { + unsigned char *dst_end = dst_data + dst_size; + + (*unpack)(src_data, dst_data, dst_end); + } + else if (src_width >= dst_width && src_height >= dst_height) + { + unsigned char *dst_end = dst_data; + + for (int y = 0; y < dst_height; y++) + { + dst_data = dst_end; + dst_end += RoundUp4(dst_width * dst_bpp / 8); + + (*unpack)(src_data, dst_data, dst_end); + + src_data += src_width * 3; + } + } + else + { + #ifdef PANIC + *logofs << "Unpack24: PANIC! Cannot unpack image. " + << "Destination area " << dst_width << "x" + << dst_height << " is not fully contained in " + << src_width << "x" << src_height << " source.\n" + << logofs_flush; + #endif + + return -1; + } + + return 1; +} + +int Unpack32To32(const T_colormask *colormask, const unsigned int *data, + unsigned int *out, unsigned int *end) +{ + #ifdef TEST + *logofs << "Unpack32To32: Unpacking " << end - out + << " bytes of data.\n" << logofs_flush; + #endif + + if (colormask -> correction_mask) + { + while (out < end) + { + if (*data == 0x00000000) + { + *out = 0x00000000; + } + else if (*data == 0xFFFFFFFF) + { + *out = 0xFFFFFFFF; + } + else + { + *out = *data | ((colormask -> correction_mask << 16) | + (colormask -> correction_mask << 8) | + colormask -> correction_mask); + } + + out += 1; + data += 1; + } + } + else + { + #ifdef TEST + *logofs << "Unpack32To32: Using bitwise copy due to null correction mask.\n" + << logofs_flush; + #endif + + memcpy((unsigned char *) out, (unsigned char *) data, end - out); + } + + return 1; +} diff --git a/nxcomp/src/Unpack.h b/nxcomp/src/Unpack.h new file mode 100644 index 000000000..faaa41d82 --- /dev/null +++ b/nxcomp/src/Unpack.h @@ -0,0 +1,149 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Unpack_H +#define Unpack_H + +#include "NXpack.h" + +#include "Z.h" + +#define LSBFirst 0 +#define MSBFirst 1 + +#define SPLIT_PATTERN 0x88 + +typedef ColorMask T_colormask; + +// +// Pixel geometry of channel's display. +// + +typedef struct +{ + unsigned int depth1_bpp; + unsigned int depth4_bpp; + unsigned int depth8_bpp; + unsigned int depth16_bpp; + unsigned int depth24_bpp; + unsigned int depth32_bpp; + + unsigned int red_mask; + unsigned int green_mask; + unsigned int blue_mask; + + unsigned int image_byte_order; + unsigned int bitmap_bit_order; + unsigned int scanline_unit; + unsigned int scanline_pad; + +} T_geometry; + +// +// Colormap is used to remap colors +// from source to destination depth. +// + +typedef struct +{ + unsigned int entries; + unsigned int *data; + +} T_colormap; + +// +// Alpha channel data is added to 32 +// bits images at the time they are +// unpacked. +// + +typedef struct +{ + unsigned int entries; + unsigned char *data; + +} T_alpha; + +// +// The ZLIB stream structure used for +// the decompression. +// + +extern z_stream unpackStream; + +// +// Initialize the ZLIB stream used for +// decompression. +// + +void UnpackInit(); + +// +// Free the ZLIB stream. +// + +void UnpackDestroy(); + +// +// Get the destination bits per pixel +// based on the drawable depth. +// + +int UnpackBitsPerPixel(T_geometry *geometry, unsigned int depth); + +// +// Unpack the source data into the X +// bitmap. +// + +int Unpack8(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size); + +int Unpack16(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size); + +int Unpack24(T_geometry *geometry, const T_colormask *colormask, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size); + +int Unpack8(T_geometry *geometry, T_colormap *colormap, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size); + +int Unpack15(T_geometry *geometry, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size); + +int Unpack16(T_geometry *geometry, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size); + +int Unpack24(T_geometry *geometry, int src_depth, int src_width, + int src_height, unsigned char *src_data, int src_size, int dst_depth, + int dst_width, int dst_height, unsigned char *dst_data, int dst_size); + +#endif /* Unpack_H */ diff --git a/nxcomp/src/Vars.c b/nxcomp/src/Vars.c new file mode 100644 index 000000000..685969677 --- /dev/null +++ b/nxcomp/src/Vars.c @@ -0,0 +1,54 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "NXvars.h" + +/* + * Allocate here instances of variables and + * pointers declared in NXvars.h. + */ + +int _NXHandleDisplayError = 0; + +NXDisplayErrorPredicate _NXDisplayErrorFunction = NULL; + +int _NXUnsetLibraryPath = 0; + +NXLostSequenceHandler _NXLostSequenceFunction = NULL; + +NXDisplayBlockHandler _NXDisplayBlockFunction = NULL; +NXDisplayWriteHandler _NXDisplayWriteFunction = NULL; +NXDisplayFlushHandler _NXDisplayFlushFunction = NULL; +NXDisplayStatisticsHandler _NXDisplayStatisticsFunction = NULL; + +#ifdef __cplusplus +} +#endif diff --git a/nxcomp/src/Version.c b/nxcomp/src/Version.c new file mode 100644 index 000000000..509bd8344 --- /dev/null +++ b/nxcomp/src/Version.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2015 Qindel Formacion y Servicios SL. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License Version 2, as */ +/* published by the Free Software Foundation. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTA- */ +/* BILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, you can request a copy from Qindel */ +/* or write to the Free Software Foundation, Inc., 51 Franklin Street, */ +/* Fifth Floor, Boston, MA 02110-1301 USA. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "NX.h" + + +static int _NXVersionMajor = -1; +static int _NXVersionMinor = -1; +static int _NXVersionPatch = -1; +static int _NXVersionMaintenancePatch = -1; + + +const char* NXVersion() { + const char *version = VERSION; + return version; +} + +void _parseNXVersion() { + char version[32]; + int i; + strcpy(version, VERSION); + + char *value; + /* Reset values to 0 if undefined */ + _NXVersionMajor = _NXVersionMinor = _NXVersionPatch = _NXVersionMaintenancePatch = 0; + + +#define NXVERSIONSEPARATOR "." + value = strtok(version, NXVERSIONSEPARATOR); + + for (i = 0; value != NULL && i < 4; i++) + { + switch (i) + { + case 0: + _NXVersionMajor = atoi(value); + break; + + case 1: + _NXVersionMinor = atoi(value); + break; + + case 2: + _NXVersionPatch = atoi(value); + break; + + case 3: + _NXVersionMaintenancePatch = atoi(value); + break; + } + + value = strtok(NULL, NXVERSIONSEPARATOR); + } +} + +int NXMajorVersion() { + if (_NXVersionMajor == -1) + _parseNXVersion(); + return _NXVersionMajor; +} +int NXMinorVersion() { + if (_NXVersionMinor == -1) + _parseNXVersion(); + return _NXVersionMinor; +} +int NXPatchVersion() { + if (_NXVersionPatch == -1) + _parseNXVersion(); + return _NXVersionPatch; +} +int NXMaintenancePatchVersion() { + if (_NXVersionMaintenancePatch == -1) + _parseNXVersion(); + return _NXVersionMaintenancePatch; +} diff --git a/nxcomp/src/WriteBuffer.cpp b/nxcomp/src/WriteBuffer.cpp new file mode 100644 index 000000000..70b4e3b53 --- /dev/null +++ b/nxcomp/src/WriteBuffer.cpp @@ -0,0 +1,500 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "Misc.h" +#include "Control.h" + +#include "WriteBuffer.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +WriteBuffer::WriteBuffer() +{ + size_ = WRITE_BUFFER_DEFAULT_SIZE; + buffer_ = new unsigned char[size_]; + length_ = 0; + index_ = NULL; + + scratchLength_ = 0; + scratchBuffer_ = NULL; + scratchOwner_ = 1; + + initialSize_ = WRITE_BUFFER_DEFAULT_SIZE; + thresholdSize_ = WRITE_BUFFER_DEFAULT_SIZE << 1; + maximumSize_ = WRITE_BUFFER_DEFAULT_SIZE << 4; + + #ifdef VALGRIND + + memset(buffer_, '\0', size_); + + #endif +} + +WriteBuffer::~WriteBuffer() +{ + if (scratchOwner_ == 1 && + scratchBuffer_ != NULL) + { + delete [] scratchBuffer_; + } + + delete [] buffer_; +} + +void WriteBuffer::setSize(unsigned int initialSize, unsigned int thresholdSize, + unsigned int maximumSize) +{ + initialSize_ = initialSize; + thresholdSize_ = thresholdSize; + maximumSize_ = maximumSize; + + #ifdef TEST + *logofs << "WriteBuffer: Set buffer sizes to " + << initialSize_ << "/" << thresholdSize_ + << "/" << maximumSize_ << ".\n" + << logofs_flush; + #endif +} + +void WriteBuffer::partialReset() +{ + if (scratchBuffer_ != NULL) + { + if (scratchOwner_) + { + #ifdef DEBUG + *logofs << "WriteBuffer: Going to delete " + << scratchLength_ << " bytes from the " + << "scratch buffer.\n" << logofs_flush; + #endif + + delete [] scratchBuffer_; + } + + scratchLength_ = 0; + scratchBuffer_ = NULL; + scratchOwner_ = 1; + } + + length_ = 0; + index_ = NULL; + + #ifdef DEBUG + *logofs << "WriteBuffer: Performed partial reset with " + << size_ << " bytes in buffer.\n" + << logofs_flush; + #endif +} + +void WriteBuffer::fullReset() +{ + if (scratchBuffer_ != NULL) + { + if (scratchOwner_ == 1) + { + #ifdef DEBUG + *logofs << "WriteBuffer: Going to delete " + << scratchLength_ << " bytes from the " + << "scratch buffer.\n" << logofs_flush; + #endif + + delete [] scratchBuffer_; + } + + scratchLength_ = 0; + scratchBuffer_ = NULL; + scratchOwner_ = 1; + } + + length_ = 0; + index_ = NULL; + + if (size_ > initialSize_) + { + #ifdef TEST + *logofs << "WriteBuffer: Reallocating a new buffer of " + << initialSize_ << " bytes.\n" << logofs_flush; + #endif + + delete [] buffer_; + + size_ = initialSize_; + + buffer_ = new unsigned char[size_]; + + if (buffer_ == NULL) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't allocate memory for " + << "X messages in context [A].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory for " + << "X messages in context [A].\n"; + + HandleAbort(); + } + + #ifdef VALGRIND + + memset(buffer_, '\0', size_); + + #endif + } + + #ifdef DEBUG + *logofs << "WriteBuffer: Performed full reset with " + << size_ << " bytes in buffer.\n" + << logofs_flush; + #endif +} + +unsigned char *WriteBuffer::addMessage(unsigned int numBytes) +{ + #ifdef DEBUG + *logofs << "WriteBuffer: Adding " << numBytes << " bytes to " + << length_ << " bytes already in buffer.\n" + << logofs_flush; + #endif + + if (numBytes > WRITE_BUFFER_OVERFLOW_SIZE) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't add a message of " + << numBytes << " bytes.\n" << logofs_flush; + + *logofs << "WriteBuffer: PANIC! Assuming error handling " + << "data in context [B].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't add a message of " + << numBytes << " bytes to write buffer.\n"; + + cerr << "Error" << ": Assuming error handling " + << "data in context [B].\n"; + + HandleAbort(); + } + else if (length_ + numBytes > size_) + { + unsigned int newSize = thresholdSize_; + + while (newSize < length_ + numBytes) + { + newSize <<= 1; + + if (newSize > maximumSize_) + { + newSize = length_ + numBytes + initialSize_; + } + } + + #ifdef TEST + *logofs << "WriteBuffer: Growing buffer from " + << size_ << " to " << newSize << " bytes.\n" + << logofs_flush; + #endif + + unsigned int indexOffset = 0; + + if (index_ && *index_) + { + indexOffset = *index_ - buffer_; + } + + size_ = newSize; + + unsigned char *newBuffer = new unsigned char[size_]; + + if (newBuffer == NULL) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't allocate memory for " + << "X messages in context [C].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory for " + << "X messages in context [C].\n"; + + HandleAbort(); + } + + #ifdef TEST + if (newSize >= maximumSize_) + { + *logofs << "WriteBuffer: WARNING! Buffer grown to reach " + << "size of " << newSize << " bytes.\n" + << logofs_flush; + } + #endif + + #ifdef VALGRIND + + memset(newBuffer, '\0', size_); + + #endif + + memcpy(newBuffer, buffer_, length_); + + #ifdef DEBUG + *logofs << "WriteBuffer: Going to delete the " + << "old buffer with new size " << size_ + << ".\n" << logofs_flush; + #endif + + delete [] buffer_; + + buffer_ = newBuffer; + + if (index_ && *index_) + { + *index_ = buffer_ + indexOffset; + } + } + + unsigned char *result = buffer_ + length_; + + length_ += numBytes; + + #ifdef DEBUG + *logofs << "WriteBuffer: Bytes in buffer are " + << length_ << " while size is " << size_ + << ".\n" << logofs_flush; + #endif + + return result; +} + +unsigned char *WriteBuffer::removeMessage(unsigned int numBytes) +{ + #ifdef TEST + *logofs << "WriteBuffer: Removing " << numBytes + << " bytes from buffer.\n" << logofs_flush; + #endif + + if (numBytes > length_) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't remove " + << numBytes << " bytes with only " << length_ + << " bytes in buffer.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Buffer underflow handling " + << "write buffer in context [D].\n"; + + HandleAbort(); + } + + length_ -= numBytes; + + #ifdef TEST + *logofs << "WriteBuffer: Bytes in buffer are now " + << length_ << " while size is " + << size_ << ".\n" << logofs_flush; + #endif + + return (buffer_ + length_); +} + +unsigned char *WriteBuffer::addScratchMessage(unsigned int numBytes) +{ + if (numBytes > WRITE_BUFFER_OVERFLOW_SIZE) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't add a message of " + << numBytes << " bytes.\n" << logofs_flush; + + *logofs << "WriteBuffer: PANIC! Assuming error handling " + << "data in context [E].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't add a message of " + << numBytes << " bytes to write buffer.\n"; + + cerr << "Error" << ": Assuming error handling " + << "data in context [E].\n"; + + HandleAbort(); + } + else if (scratchBuffer_ != NULL) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't add a message of " + << numBytes << " bytes with " << scratchLength_ + << " bytes already in scratch buffer.\n" + << logofs_flush; + + *logofs << "WriteBuffer: PANIC! Assuming error handling " + << "data in context [F].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't add a message of " + << numBytes << " bytes with " << scratchLength_ + << " bytes already in scratch buffer.\n"; + + cerr << "Error" << ": Assuming error handling " + << "data in context [F].\n"; + + HandleAbort(); + } + + #ifdef DEBUG + *logofs << "WriteBuffer: Adding " << numBytes << " bytes " + << "to scratch buffer.\n" << logofs_flush; + #endif + + unsigned char *newBuffer = new unsigned char[numBytes]; + + if (newBuffer == NULL) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't allocate memory for " + << "X messages in context [G].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't allocate memory for " + << "X messages in context [G].\n"; + + HandleAbort(); + } + + #ifdef VALGRIND + + memset(newBuffer, '\0', numBytes); + + #endif + + scratchBuffer_ = newBuffer; + scratchOwner_ = 1; + scratchLength_ = numBytes; + + return newBuffer; +} + +unsigned char *WriteBuffer::addScratchMessage(unsigned char *newBuffer, unsigned int numBytes) +{ + if (numBytes > WRITE_BUFFER_OVERFLOW_SIZE) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't add a message of " + << numBytes << " bytes.\n" << logofs_flush; + + *logofs << "WriteBuffer: PANIC! Assuming error handling " + << "data in context [H].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't add a message of " + << numBytes << " bytes to write buffer.\n"; + + cerr << "Error" << ": Assuming error handling " + << "data in context [H].\n"; + + HandleAbort(); + } + else if (scratchBuffer_ != NULL) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't add a foreign " + << "message of " << numBytes << " bytes with " + << scratchLength_ << " bytes already in " + << "scratch buffer.\n" << logofs_flush; + + *logofs << "WriteBuffer: PANIC! Assuming error handling " + << "data in context [I].\n" << logofs_flush; + #endif + + cerr << "Error" << ": Can't add a foreign message of " + << numBytes << " bytes with " << scratchLength_ + << " bytes already in scratch buffer.\n"; + + cerr << "Error" << ": Assuming error handling " + << "data in context [I].\n"; + + HandleAbort(); + } + + #ifdef DEBUG + *logofs << "WriteBuffer: Adding " << numBytes << " bytes " + << "from a foreign message to scratch buffer.\n" + << logofs_flush; + #endif + + scratchBuffer_ = newBuffer; + scratchLength_ = numBytes; + scratchOwner_ = 0; + + return newBuffer; +} + +void WriteBuffer::removeScratchMessage() +{ + #ifdef TEST + + if (scratchLength_ == 0 || scratchBuffer_ == NULL) + { + #ifdef PANIC + *logofs << "WriteBuffer: PANIC! Can't remove non existent scratch message.\n" + << logofs_flush; + #endif + + cerr << "Error" << ": Can't remove non existent scratch message.\n"; + + HandleAbort(); + } + + *logofs << "WriteBuffer: Removing " << scratchLength_ + << " bytes from scratch buffer.\n" + << logofs_flush; + + #endif + + if (scratchOwner_ == 1) + { + #ifdef DEBUG + *logofs << "WriteBuffer: Going to delete " + << scratchLength_ << " bytes from the " + << "scratch buffer.\n" << logofs_flush; + #endif + + delete [] scratchBuffer_; + } + + scratchLength_ = 0; + scratchBuffer_ = NULL; + scratchOwner_ = 1; +} diff --git a/nxcomp/src/WriteBuffer.h b/nxcomp/src/WriteBuffer.h new file mode 100644 index 000000000..ce408e210 --- /dev/null +++ b/nxcomp/src/WriteBuffer.h @@ -0,0 +1,134 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef WriteBuffer_H +#define WriteBuffer_H + +#include "Misc.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define WRITE_BUFFER_DEFAULT_SIZE 16384 + +// +// Adjust for the biggest reply that we could receive. +// This is likely to be a reply to a X_ListFonts where +// user has a large amount of installed fonts. +// + +#define WRITE_BUFFER_OVERFLOW_SIZE 4194304 + +class WriteBuffer +{ + public: + + WriteBuffer(); + + ~WriteBuffer(); + + void setSize(unsigned int initialSize, unsigned int thresholdSize, + unsigned int maximumSize); + + unsigned char *addMessage(unsigned int numBytes); + + unsigned char *removeMessage(unsigned int numBytes); + + unsigned char *addScratchMessage(unsigned int numBytes); + + // + // This form allows user to provide its own + // buffer as write buffer's scratch area. + // + + unsigned char *addScratchMessage(unsigned char *newBuffer, unsigned int numBytes); + + void removeScratchMessage(); + + void partialReset(); + + void fullReset(); + + unsigned char *getData() const + { + return buffer_; + } + + unsigned int getLength() const + { + return length_; + } + + unsigned int getAvailable() const + { + return (size_ - length_); + } + + unsigned char *getScratchData() const + { + return scratchBuffer_; + } + + unsigned int getScratchLength() const + { + return scratchLength_; + } + + unsigned int getTotalLength() const + { + return (length_ + scratchLength_); + } + + void registerPointer(unsigned char **pointer) + { + index_ = pointer; + } + + void unregisterPointer() + { + index_ = 0; + } + + private: + + unsigned int size_; + unsigned int length_; + + unsigned char *buffer_; + unsigned char **index_; + + unsigned int scratchLength_; + unsigned char *scratchBuffer_; + + int scratchOwner_; + + unsigned int initialSize_; + unsigned int thresholdSize_; + unsigned int maximumSize_; +}; + +#endif /* WriteBuffer_H */ diff --git a/nxcomp/src/XidCache.cpp b/nxcomp/src/XidCache.cpp new file mode 100644 index 000000000..ab6574cc9 --- /dev/null +++ b/nxcomp/src/XidCache.cpp @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Control.h" + +#include "XidCache.h" + +XidCache::XidCache() +{ + for (int i = 0; i < 256; i++) + { + base_[i] = new IntCache(8); + } + + slot_ = 0; + last_ = 0; +} + +XidCache::~XidCache() +{ + for (int i = 0; i < 256; i++) + { + delete base_[i]; + } +} diff --git a/nxcomp/src/XidCache.h b/nxcomp/src/XidCache.h new file mode 100644 index 000000000..8a09ef9b1 --- /dev/null +++ b/nxcomp/src/XidCache.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef XidCache_H +#define XidCache_H + +#include "IntCache.h" + +class XidCache +{ + friend class EncodeBuffer; + friend class DecodeBuffer; + + public: + + XidCache(); + ~XidCache(); + + private: + + IntCache *base_[256]; + + unsigned int slot_; + unsigned int last_; +}; + +#endif /* XidCache_H */ diff --git a/nxcomp/src/Z.cpp b/nxcomp/src/Z.cpp new file mode 100644 index 000000000..af3b380f2 --- /dev/null +++ b/nxcomp/src/Z.cpp @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Z.h" +#include "Misc.h" + +int ZCompress(z_stream *stream, unsigned char *dest, unsigned int *destLen, + const unsigned char *source, unsigned int sourceLen) +{ + // + // Deal with the possible overflow. + // + + if (stream -> total_out & 0x80000000) + { + #ifdef TEST + *logofs << "ZCompress: Reset stream counters with " + << "total in " << stream -> total_in + << " and total out " << stream -> total_out + << ".\n" << logofs_flush; + #endif + + stream -> total_in = 0; + stream -> total_out = 0; + } + + unsigned int saveOut = stream -> total_out; + + stream -> next_in = (Bytef *) source; + stream -> avail_in = sourceLen; + + // + // Check if the source is bigger than + // 64K on 16-bit machine. + // + + #ifdef MAXSEG_64K + + if ((uLong) stream -> avail_in != sourceLen) return Z_BUF_ERROR; + + #endif + + stream -> next_out = dest; + stream -> avail_out = *destLen; + + #ifdef MAXSEG_64K + + if ((uLong) stream -> avail_out != *destLen) return Z_BUF_ERROR; + + #endif + + int result = deflate(stream, Z_FINISH); + + if (result != Z_STREAM_END) + { + deflateReset(stream); + + return (result == Z_OK ? Z_BUF_ERROR : result); + } + + *destLen = stream -> total_out - saveOut; + + result = deflateReset(stream); + + return result; +} + +int ZDecompress(z_stream *stream, unsigned char *dest, unsigned int *destLen, + const unsigned char *source, unsigned int sourceLen) +{ + stream -> next_in = (Bytef *) source; + stream -> avail_in = sourceLen; + + // + // Deal with the possible overflow. + // + + if (stream -> total_out & 0x80000000) + { + #ifdef TEST + *logofs << "ZDecompress: Reset stream counters with " + << "total in " << stream -> total_in + << " and total out " << stream -> total_out + << ".\n" << logofs_flush; + #endif + + stream -> total_in = 0; + stream -> total_out = 0; + } + + unsigned int saveOut = stream -> total_out; + + if (stream -> avail_in != sourceLen) + { + return Z_BUF_ERROR; + } + + stream -> next_out = dest; + stream -> avail_out = *destLen; + + if (stream -> avail_out != *destLen) + { + return Z_BUF_ERROR; + } + + int result = inflate(stream, Z_FINISH); + + if (result != Z_STREAM_END) + { + inflateReset(stream); + + return (result == Z_OK ? Z_BUF_ERROR : result); + } + + *destLen = stream -> total_out - saveOut; + + result = inflateReset(stream); + + return result; +} diff --git a/nxcomp/src/Z.h b/nxcomp/src/Z.h new file mode 100644 index 000000000..3a6d684c2 --- /dev/null +++ b/nxcomp/src/Z.h @@ -0,0 +1,37 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXCOMP, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE.nxcomp which comes in the */ +/* source distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef Z_H +#define Z_H + +#include + +int ZCompress(z_stream *stream, unsigned char *dest, unsigned int *destLen, + const unsigned char *source, unsigned int sourceLen); + +int ZDecompress(z_stream *stream, unsigned char *dest, unsigned int *destLen, + const unsigned char *source, unsigned int sourceLen); + +#endif /* Z_H */ diff --git a/nxproxy/src/Makefile.am b/nxproxy/src/Makefile.am index 5ec1f9401..60ace92ce 100644 --- a/nxproxy/src/Makefile.am +++ b/nxproxy/src/Makefile.am @@ -9,9 +9,9 @@ nxproxy_SOURCES = \ $(NULL) nxproxy_LDADD = \ - -L$(top_srcdir)/../nxcomp/ -lXcomp \ + -L$(top_srcdir)/../nxcomp/src/.libs -lXcomp \ $(NULL) AM_CPPFLAGS = \ - -I$(top_srcdir)/../nxcomp/ \ + -I$(top_srcdir)/../nxcomp/include/ \ $(NULL) -- cgit v1.2.3