root/OpenSceneGraph/trunk/src/osgPlugins/vnc/ReaderWriterVNC.cpp @ 12851

Revision 12851, 11.7 kB (checked in by robert, 2 years ago)

Added password support into osgvnc example and vnc plugin

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1999-2008 Robert Osfield
2 *
3 * This software is open source and may be redistributed and/or modified under 
4 * the terms of the GNU General Public License (GPL) version 2.0.
5 * The full license is in LICENSE.txt file included with this distribution,.
6 *
7 * This software is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * include LICENSE.txt for more details.
11*/
12
13#include <osg/Timer>
14
15#include <osgDB/ReaderWriter>
16#include <osgDB/FileNameUtils>
17#include <osgDB/Registry>
18
19#include <osgWidget/VncClient>
20
21extern "C" {
22#include <rfb/rfbclient.h>
23}
24
25class LibVncImage : public osgWidget::VncImage
26{
27    public:
28   
29        LibVncImage();
30
31        bool connect(const std::string& hostname);
32
33        void close();
34       
35        virtual bool sendPointerEvent(int x, int y, int buttonMask);
36
37        double getTimeOfLastUpdate() const { return _timeOfLastUpdate; }
38        double getTimeOfLastRender() const { return _timeOfLastRender; }
39
40        double time() const { return osg::Timer::instance()->time_s(); }
41
42        virtual bool sendKeyEvent(int key, bool keyDown);
43
44        virtual void setFrameLastRendered(const osg::FrameStamp* frameStamp);
45
46        void updated();
47
48        static rfbBool resizeImage(rfbClient* client);
49       
50        static void updateImage(rfbClient* client,int x,int y,int w,int h);
51       
52        static void passwordCheck(rfbClient* client,const char* encryptedPassWord,int len);
53        static char* getPassword(rfbClient* client);
54
55        std::string                 _username;
56        std::string                 _password;
57        double                      _timeOfLastUpdate;
58        double                      _timeOfLastRender;
59
60        bool                        _active;
61        osg::ref_ptr<osg::RefBlock> _inactiveBlock;
62
63    protected:
64   
65        virtual ~LibVncImage();
66
67        class RfbThread : public osg::Referenced, public OpenThreads::Thread
68        {
69        public:
70
71            RfbThread(rfbClient* client, LibVncImage* image):
72                _client(client),
73                _image(image),
74                _done(false) {}
75
76            virtual ~RfbThread()
77            {
78                _done = true;
79                while(isRunning())
80                {
81                    OpenThreads::Thread::YieldCurrentThread();
82                }
83            }
84
85            virtual void run()
86            {
87                do
88                {
89                    if (_image->_active)
90                    {               
91                        int i=WaitForMessage(_client,5000);
92                        if(i<0)
93                            return;
94
95                        if(i)
96                        {
97                            OSG_INFO<<"VNC Handling "<<i<<" messages"<<std::endl;
98                       
99                            if(!HandleRFBServerMessage(_client))
100                            return;
101
102                            _image->updated();
103                        }
104                    }
105                    else
106                    {
107                        _image->_inactiveBlock->block();
108                    }
109                   
110                   
111                    double deltaTime = _image->getTimeOfLastRender() - _image->getTimeOfLastUpdate();
112                    if (deltaTime<-0.01)
113                    {
114                        //OSG_NOTICE<<"Inactive"<<std::endl;
115                        //_image->_active = false;
116                    }
117                    else
118                    {
119                        _image->_active = true;
120                    }
121
122                } while (!_done && !testCancel());
123            }
124
125            rfbClient*                      _client;
126            osg::observer_ptr<LibVncImage>  _image;
127            bool                            _done;
128
129        };
130
131    public:
132
133        rfbClient* _client;
134
135        osg::ref_ptr<RfbThread>     _rfbThread;
136     
137};
138
139LibVncImage::LibVncImage():
140    _client(0)
141{
142    // setPixelBufferObject(new osg::PixelBufferObject(this);
143
144    _inactiveBlock = new osg::RefBlock;
145}
146
147LibVncImage::~LibVncImage()
148{
149    close();
150}
151
152static rfbBool rfbInitConnection(rfbClient* client)
153{
154  /* Unless we accepted an incoming connection, make a TCP connection to the
155     given VNC server */
156
157  if (!client->listenSpecified) {
158    if (!client->serverHost || !ConnectToRFBServer(client,client->serverHost,client->serverPort))
159      return FALSE;
160  }
161
162  /* Initialise the VNC connection, including reading the password */
163
164  if (!InitialiseRFBConnection(client))
165    return FALSE;
166
167  if (!SetFormatAndEncodings(client))
168    return FALSE;
169
170  client->width=client->si.framebufferWidth;
171  client->height=client->si.framebufferHeight;
172  client->MallocFrameBuffer(client);
173
174  if (client->updateRect.x < 0) {
175    client->updateRect.x = client->updateRect.y = 0;
176    client->updateRect.w = client->width;
177    client->updateRect.h = client->height;
178  }
179
180  if (client->appData.scaleSetting>1)
181  {
182      if (!SendScaleSetting(client, client->appData.scaleSetting))
183          return FALSE;
184      if (!SendFramebufferUpdateRequest(client,
185                  client->updateRect.x / client->appData.scaleSetting,
186                  client->updateRect.y / client->appData.scaleSetting,
187                  client->updateRect.w / client->appData.scaleSetting,
188                  client->updateRect.h / client->appData.scaleSetting,
189                  FALSE))
190          return FALSE;
191  }
192  else
193  {
194      if (!SendFramebufferUpdateRequest(client,
195                  client->updateRect.x, client->updateRect.y,
196                  client->updateRect.w, client->updateRect.h,
197                  FALSE))
198      return FALSE;
199  }
200
201  return TRUE;
202}
203
204void LibVncImage::passwordCheck(rfbClient* client,const char* encryptedPassWord,int len)
205{
206    OSG_NOTICE<<"LibVncImage::passwordCheck"<<std::endl;
207}
208
209char* LibVncImage::getPassword(rfbClient* client)
210{
211    LibVncImage* image = (LibVncImage*)(rfbClientGetClientData(client, 0));
212    OSG_NOTICE<<"LibVncImage::getPassword "<<image->_password<<std::endl;
213    return strdup(image->_password.c_str());
214}
215
216
217bool LibVncImage::connect(const std::string& hostname)
218{
219    if (hostname.empty()) return false;
220
221    if (_client) close();
222
223    _client = rfbGetClient(8,3,4);
224    _client->canHandleNewFBSize = TRUE;
225    _client->MallocFrameBuffer = resizeImage;
226    _client->GotFrameBufferUpdate = updateImage;
227    _client->HandleKeyboardLedState = 0;
228    _client->HandleTextChat = 0;
229
230    // provide the password if we have one assigned
231    if (!_password.empty())  _client->GetPassword = getPassword;
232
233    rfbClientSetClientData(_client, 0, this);
234   
235    _client->serverHost = strdup(hostname.c_str());
236
237    // _client->serverPort = ;
238    // _client->appData.qualityLevel = ;
239    // _client->appData.encodings = ;
240    // _client->appData.compressLevel = ;
241    // _client->appData.scaleSetting = ;
242
243    if(rfbInitConnection(_client))
244    {
245        _rfbThread = new RfbThread(_client, this);
246        _rfbThread->startThread();
247       
248        return true;
249    }
250    else
251    {
252        close();
253       
254        return false;
255    }
256}
257
258
259void LibVncImage::close()
260{
261    if (_rfbThread.valid())
262    {
263        _inactiveBlock->release();
264
265        // stop the client thread
266        _rfbThread = 0;
267    }
268
269    if (_client)
270    {
271        // close the client
272        rfbClientCleanup(_client);
273        _client = 0;
274    }
275}
276
277
278rfbBool LibVncImage::resizeImage(rfbClient* client)
279{
280    osg::Image* image = (osg::Image*)(rfbClientGetClientData(client, 0));
281   
282    int width = client->width;
283    int height = client->height;
284    int depth = client->format.bitsPerPixel;
285
286    OSG_NOTICE<<"resize "<<width<<", "<<height<<", "<<depth<<" image = "<<image<<std::endl;
287    PrintPixelFormat(&(client->format));
288
289#ifdef __APPLE__
290    // feedback is that Mac's have an endian swap even though the PixelFormat results see under OSX are identical.
291    bool swap = true;
292#else
293    bool swap = client->format.redShift!=0;
294#endif
295
296    GLenum gl_pixelFormat = swap ? GL_BGRA : GL_RGBA;
297
298    image->allocateImage(width, height, 1, gl_pixelFormat, GL_UNSIGNED_BYTE);
299    image->setInternalTextureFormat(GL_RGBA);
300
301
302   
303    client->frameBuffer= (uint8_t*)(image->data());
304   
305    return TRUE;
306}
307
308void LibVncImage::updateImage(rfbClient* client,int x,int y,int w,int h)
309{
310    osg::Image* image = (osg::Image*)(rfbClientGetClientData(client, 0));
311    image->dirty();
312}
313
314bool LibVncImage::sendPointerEvent(int x, int y, int buttonMask)
315{
316    if (_client)
317    {
318        SendPointerEvent(_client ,x, y, buttonMask);
319        return true;
320    }
321    return false;
322}
323
324bool LibVncImage::sendKeyEvent(int key, bool keyDown)
325{
326    if (_client)
327    {
328        SendKeyEvent(_client, key, keyDown ? TRUE : FALSE);
329        return true;
330    }
331    return false;
332}
333
334
335void LibVncImage::setFrameLastRendered(const osg::FrameStamp*)
336{
337    _timeOfLastRender = time();
338
339    if (!_active) _inactiveBlock->release();
340    _active = true;
341}
342
343void LibVncImage::updated()
344{
345    _timeOfLastUpdate = time();
346}
347
348class ReaderWriterVNC : public osgDB::ReaderWriter
349{
350    public:
351   
352        ReaderWriterVNC()
353        {
354            supportsExtension("vnc","VNC plugin");
355        }
356       
357        virtual const char* className() const { return "VNC plugin"; }
358
359        virtual osgDB::ReaderWriter::ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const
360        {
361            return readImage(file,options);
362        }
363
364        virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
365        {
366            if (!osgDB::equalCaseInsensitive(osgDB::getFileExtension(fileName),"vnc"))
367            {
368                return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
369            }
370
371            std::string hostname = osgDB::getNameLessExtension(fileName);
372           
373            OSG_NOTICE<<"Hostname = "<<hostname<<std::endl;
374
375            osg::ref_ptr<LibVncImage> image = new LibVncImage;
376            image->setDataVariance(osg::Object::DYNAMIC);           
377            image->setOrigin(osg::Image::TOP_LEFT);
378
379            const osgDB::AuthenticationMap* authenticationMap = (options && options->getAuthenticationMap()) ?
380                    options->getAuthenticationMap() :
381                    osgDB::Registry::instance()->getAuthenticationMap();
382
383            const osgDB::AuthenticationDetails* details = authenticationMap ?
384                authenticationMap->getAuthenticationDetails(hostname) :
385                0;
386
387            // configure authentication if required.
388            if (details)
389            {
390                OSG_NOTICE<<"Passing in password = "<<details->password<<std::endl;
391
392                image->_username = details->username;
393                image->_password = details->password;
394            }
395
396            if (!image->connect(hostname))
397            {
398                return "Could not connect to "+hostname;
399            }
400           
401            return image.get();
402        }
403       
404        virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
405        {
406            osgDB::ReaderWriter::ReadResult result = readImage(fileName, options);
407            if (!result.validImage()) return result;
408           
409            osg::ref_ptr<osgWidget::VncClient> vncClient = new osgWidget::VncClient();
410            if (vncClient->assign(dynamic_cast<osgWidget::VncImage*>(result.getImage())))
411            {
412                return vncClient.release();
413            }
414            else
415            {
416                return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
417            }
418        }
419};
420
421// now register with Registry to instantiate the above
422// reader/writer.
423REGISTER_OSGPLUGIN(vnc, ReaderWriterVNC)
Note: See TracBrowser for help on using the browser.