~ubuntu-branches/debian/lenny/italc/lenny

« back to all changes in this revision

Viewing changes to ica/src/demo_server.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-06-17 13:46:54 UTC
  • mto: This revision was merged to the branch mainline in revision 5.
  • Revision ID: james.westby@ubuntu.com-20080617134654-2y5m7ki93r5c1ysf
Tags: upstream-1.0.9~rc3
ImportĀ upstreamĀ versionĀ 1.0.9~rc3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * demo_server.cpp - multi-threaded slim VNC-server for demo-purposes (optimized
 
3
 *                   for lot of clients accessing server in read-only-mode)
 
4
 *
 
5
 * Copyright (c) 2006-2008 Tobias Doerffel <tobydox/at/users/dot/sf/dot/net>
 
6
 *  
 
7
 * This file is part of iTALC - http://italc.sourceforge.net
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU General Public
 
11
 * License as published by the Free Software Foundation; either
 
12
 * version 2 of the License, or (at your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
 * General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public
 
20
 * License along with this program (see COPYING); if not, write to the
 
21
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
22
 * Boston, MA 02111-1307, USA.
 
23
 *
 
24
 */
 
25
 
 
26
 
 
27
#include <QtCore/QDateTime>
 
28
#include <QtCore/QTimer>
 
29
#include <QtCore/QVector>
 
30
#include <QtGui/QCursor>
 
31
 
 
32
 
 
33
#include "demo_server.h"
 
34
#include "isd_server.h"
 
35
#include "italc_rfb_ext.h"
 
36
#include "minilzo.h"
 
37
#include "ivs.h"
 
38
 
 
39
 
 
40
const int CURSOR_UPDATE_TIME = 30;
 
41
 
 
42
int demoServer::s_numOfInstances = 0;
 
43
 
 
44
 
 
45
demoServer::demoServer( IVS * _ivs_conn, int _quality, quint16 _port,
 
46
                                                        QTcpSocket * _parent ) :
 
47
        QTcpServer( _parent ),
 
48
        m_conn( new ivsConnection(
 
49
                        QHostAddress( QHostAddress::LocalHost ).toString() +
 
50
                                        ":" + QString::number(
 
51
                                                _ivs_conn->serverPort() ),
 
52
                        static_cast<ivsConnection::quality>(
 
53
                                ivsConnection::QualityDemoLow +
 
54
                                                qBound( 0, _quality, 2 ) ),
 
55
                                _ivs_conn->runningInSeparateProcess() ) ),
 
56
        m_updaterThread( new updaterThread( m_conn ) )
 
57
{
 
58
        ++s_numOfInstances;
 
59
 
 
60
        if( listen( QHostAddress::Any, _port ) == FALSE )
 
61
        {
 
62
                qCritical( "demoServer::demoServer(): "
 
63
                                        "could not start demo-server!" );
 
64
                return;
 
65
        }
 
66
 
 
67
        m_updaterThread->start(/* QThread::HighPriority*/ );
 
68
 
 
69
}
 
70
 
 
71
 
 
72
 
 
73
 
 
74
demoServer::~demoServer()
 
75
{
 
76
        --s_numOfInstances;
 
77
 
 
78
        delete m_updaterThread;
 
79
        delete m_conn;
 
80
}
 
81
 
 
82
 
 
83
 
 
84
 
 
85
void demoServer::incomingConnection( int _sd )
 
86
{
 
87
        new demoServerClient( _sd, m_conn );
 
88
}
 
89
 
 
90
 
 
91
 
 
92
 
 
93
 
 
94
 
 
95
demoServer::updaterThread::updaterThread( ivsConnection * _ic ) :
 
96
        QThread(),
 
97
        m_conn( _ic ),
 
98
        m_quit( FALSE )
 
99
{
 
100
}
 
101
 
 
102
 
 
103
 
 
104
 
 
105
demoServer::updaterThread::~updaterThread()
 
106
{
 
107
        m_quit = TRUE;
 
108
        wait();
 
109
}
 
110
 
 
111
 
 
112
 
 
113
 
 
114
void demoServer::updaterThread::run( void )
 
115
{
 
116
        int i = 0;
 
117
        while( !m_quit )
 
118
        {
 
119
                while( !m_quit && m_conn->state() != ivsConnection::Connected &&
 
120
                                m_conn->open() != ivsConnection::Connected )
 
121
                {
 
122
                        qWarning( "demoServer::updaterThread::run(): "
 
123
                                        "could not connect to local IVS!" );
 
124
                        sleep( 1 );
 
125
                }
 
126
                msleep( 20 );
 
127
                m_conn->handleServerMessages( ( i = ( i + 1 ) % 2 ) == 0 );
 
128
        }
 
129
        m_conn->gracefulClose();
 
130
}
 
131
 
 
132
 
 
133
 
 
134
 
 
135
 
 
136
 
 
137
 
 
138
 
 
139
 
 
140
 
 
141
 
 
142
demoServerClient::demoServerClient( int _sd, const ivsConnection * _conn ) :
 
143
        QThread(),
 
144
        m_dataMutex(),
 
145
        m_changedRegion(),
 
146
        m_lastCursorPos(),
 
147
        m_cursorShapeChanged( TRUE ),
 
148
        m_cursorPosChanged( FALSE ),
 
149
        m_socketDescriptor( _sd ),
 
150
        m_sock( NULL ),
 
151
        m_conn( _conn ),
 
152
        m_otherEndianess( FALSE ),
 
153
        m_lzoWorkMem( new Q_UINT8[sizeof( lzo_align_t ) *
 
154
                        ( ( ( LZO1X_1_MEM_COMPRESS ) +
 
155
                                        ( sizeof( lzo_align_t ) - 1 ) ) /
 
156
                                                sizeof( lzo_align_t ) ) ] )
 
157
{
 
158
        QTimer::singleShot( CURSOR_UPDATE_TIME, this,
 
159
                                        SLOT( checkForCursorMovement() ) );
 
160
        start();
 
161
}
 
162
 
 
163
 
 
164
 
 
165
 
 
166
demoServerClient::~demoServerClient()
 
167
{
 
168
        exit();
 
169
        wait();
 
170
        delete[] m_lzoWorkMem;
 
171
}
 
172
 
 
173
 
 
174
 
 
175
 
 
176
void demoServerClient::updateRegion( const QRegion & _reg )
 
177
{
 
178
        m_dataMutex.lock();
 
179
        m_changedRegion += _reg;
 
180
        m_dataMutex.unlock();
 
181
}
 
182
 
 
183
 
 
184
 
 
185
 
 
186
void demoServerClient::updateCursorShape( void )
 
187
{
 
188
        m_cursorShapeChanged = TRUE;
 
189
}
 
190
 
 
191
 
 
192
 
 
193
 
 
194
void demoServerClient::checkForCursorMovement( void )
 
195
{
 
196
        m_dataMutex.lock();
 
197
        if( m_lastCursorPos != QCursor::pos() )
 
198
        {
 
199
                m_lastCursorPos = QCursor::pos();
 
200
                m_cursorPosChanged = TRUE;
 
201
        }
 
202
        m_dataMutex.unlock();
 
203
        QTimer::singleShot( CURSOR_UPDATE_TIME, this,
 
204
                                        SLOT( checkForCursorMovement() ) );
 
205
}
 
206
 
 
207
 
 
208
 
 
209
 
 
210
void demoServerClient::moveCursor( void )
 
211
{
 
212
        m_dataMutex.lock();
 
213
        if( m_cursorPosChanged )
 
214
        {
 
215
                m_cursorPosChanged = FALSE;
 
216
                const rfbFramebufferUpdateMsg m =
 
217
                {
 
218
                        rfbFramebufferUpdate,
 
219
                        0,
 
220
                        swap16IfLE( 1 )
 
221
                } ;
 
222
 
 
223
                m_sock->write( (const char *) &m, sizeof( m ) );
 
224
 
 
225
                const rfbRectangle rr =
 
226
                {
 
227
                        swap16IfLE( m_lastCursorPos.x() ),
 
228
                        swap16IfLE( m_lastCursorPos.y() ),
 
229
                        swap16IfLE( 0 ),
 
230
                        swap16IfLE( 0 )
 
231
                } ;
 
232
 
 
233
                const rfbFramebufferUpdateRectHeader rh =
 
234
                {
 
235
                        rr,
 
236
                        swap32IfLE( rfbEncodingPointerPos )
 
237
                } ;
 
238
 
 
239
                m_sock->write( (const char *) &rh, sizeof( rh ) );
 
240
                m_sock->flush();
 
241
        }
 
242
        m_dataMutex.unlock();
 
243
}
 
244
 
 
245
 
 
246
 
 
247
 
 
248
void demoServerClient::processClient( void )
 
249
{
 
250
        m_dataMutex.lock();
 
251
        while( m_sock->bytesAvailable() > 0 )
 
252
        {
 
253
                Q_UINT8 cmd;
 
254
                if( m_sock->read( (char *) &cmd, sizeof( cmd ) ) <= 0 )
 
255
                {
 
256
                        qWarning( "demoServerClient::processClient(): "
 
257
                                                        "could not read cmd" );
 
258
                        continue;
 
259
                }
 
260
 
 
261
                if( cmd != rfbFramebufferUpdateRequest )
 
262
                {
 
263
                        continue;
 
264
                }
 
265
 
 
266
                if( m_changedRegion.isEmpty() )
 
267
                {
 
268
                        continue;
 
269
                }
 
270
 
 
271
                // extract single (non-overlapping) rects out of changed region
 
272
                // this way we avoid lot of simliar/overlapping rectangles,
 
273
                // e.g. if we didn't get an update-request for a quite long time
 
274
                // and there were a lot of updates - at the end we don't send
 
275
                // more than the whole screen one time
 
276
                const QVector<QRect> r = m_changedRegion.rects();
 
277
 
 
278
                // no we gonna post all changed rects!
 
279
                const rfbFramebufferUpdateMsg m =
 
280
                {
 
281
                        rfbFramebufferUpdate,
 
282
                        0,
 
283
                        swap16IfLE( r.size() +
 
284
                                        ( m_cursorShapeChanged ? 1 : 0 ) )
 
285
                } ;
 
286
 
 
287
                m_sock->write( (const char *) &m, sizeof( m ) );
 
288
                // process each rect
 
289
                for( QVector<QRect>::const_iterator it = r.begin();
 
290
                                                        it != r.end(); ++it )
 
291
                {
 
292
                        const rfbRectangle rr =
 
293
                        {
 
294
                                swap16IfLE( it->x() ),
 
295
                                swap16IfLE( it->y() ),
 
296
                                swap16IfLE( it->width() ),
 
297
                                swap16IfLE( it->height() )
 
298
                        } ;
 
299
 
 
300
                        const rfbFramebufferUpdateRectHeader rh =
 
301
                        {
 
302
                                rr,
 
303
                                swap32IfLE( rfbEncodingItalc )
 
304
                        } ;
 
305
 
 
306
                        m_sock->write( (const char *) &rh, sizeof( rh ) );
 
307
 
 
308
                        const QImage & i = m_conn->screen();
 
309
                        italcRectEncodingHeader hdr = { 0, 0, 0 } ;
 
310
 
 
311
                        const Q_UINT16 w = it->width();
 
312
                        const Q_UINT16 h = it->height();
 
313
 
 
314
                        // we only compress if it's enough data, otherwise
 
315
                        // there's too much overhead
 
316
                        if( w * h > 1024 )
 
317
                        {
 
318
 
 
319
        hdr.compressed = 1;
 
320
        QRgb last_pix = *( (QRgb *) i.scanLine( it->y() ) + it->x() );
 
321
        Q_UINT8 rle_cnt = 0;
 
322
        Q_UINT8 rle_sub = 1;
 
323
        Q_UINT8 * out = new Q_UINT8[w * h * sizeof( QRgb )+16];
 
324
        Q_UINT8 * out_ptr = out;
 
325
        for( Q_UINT16 y = it->y(); y < it->y() + h; ++y )
 
326
        {
 
327
                const QRgb * data = ( (const QRgb *) i.scanLine( y ) ) +
 
328
                                                                        it->x();
 
329
                for( Q_UINT16 x = 0; x < w; ++x )
 
330
                {
 
331
                        if( data[x] != last_pix || rle_cnt > 254 )
 
332
                        {
 
333
                                *( (QRgb *) out_ptr ) = swap32IfBE( last_pix );
 
334
                                *( out_ptr + 3 ) = rle_cnt - rle_sub;
 
335
                                out_ptr += 4;
 
336
                                last_pix = data[x];
 
337
                                rle_cnt = rle_sub = 0;
 
338
                        }
 
339
                        else
 
340
                        {
 
341
                                ++rle_cnt;
 
342
                        }
 
343
                }
 
344
        }
 
345
 
 
346
        // flush RLE-loop
 
347
        *( (QRgb *) out_ptr ) = last_pix;
 
348
        *( out_ptr + 3 ) = rle_cnt;
 
349
        out_ptr += 4;
 
350
 
 
351
        hdr.bytesRLE = out_ptr - out;
 
352
        lzo_uint bytes_lzo = hdr.bytesRLE + hdr.bytesRLE / 16 + 67;
 
353
        Q_UINT8 * comp = new Q_UINT8[bytes_lzo];
 
354
        lzo1x_1_compress( (const unsigned char *) out, (lzo_uint) hdr.bytesRLE,
 
355
                                (unsigned char *) comp,
 
356
                                &bytes_lzo, m_lzoWorkMem );
 
357
        hdr.bytesRLE = swap32IfLE( hdr.bytesRLE );
 
358
        hdr.bytesLZO = swap32IfLE( bytes_lzo );
 
359
 
 
360
        m_sock->write( (const char *) &hdr, sizeof( hdr ) );
 
361
        m_sock->write( (const char *) comp, swap32IfLE( hdr.bytesLZO ) );
 
362
        delete[] out;
 
363
        delete[] comp;
 
364
 
 
365
                        }
 
366
                        else
 
367
                        {
 
368
        m_sock->write( (const char *) &hdr, sizeof( hdr ) );
 
369
        if( m_otherEndianess )
 
370
        {
 
371
                Q_UINT32 * buf = new Q_UINT32[w];
 
372
                for( Q_UINT16 y = 0; y < h; ++y )
 
373
                {
 
374
                        const QRgb * src = (const QRgb *) i.scanLine( it->y() + y ) +
 
375
                                                                                it->x();
 
376
                        for( Q_UINT16 x = 0; x < w; ++x, ++src )
 
377
                        {
 
378
                                buf[x] = swap32( *src );
 
379
                        }
 
380
                        m_sock->write( (const char *) buf, w * sizeof( QRgb ) );
 
381
                }
 
382
                delete[] buf;
 
383
        }
 
384
        else
 
385
        {
 
386
                for( Q_UINT16 y = 0; y < h; ++y )
 
387
                {
 
388
                        m_sock->write( (const char *)
 
389
                                ( (const QRgb *) i.scanLine( it->y() + y ) + it->x() ),
 
390
                                                                w * sizeof( QRgb ) );
 
391
                }
 
392
        }
 
393
                        }
 
394
                }
 
395
 
 
396
                if( m_cursorShapeChanged )
 
397
                {
 
398
                        const QImage cur = m_conn->cursorShape();
 
399
                        const rfbRectangle rr =
 
400
                        {
 
401
                                swap16IfLE( m_conn->cursorHotSpot().x() ),
 
402
                                swap16IfLE( m_conn->cursorHotSpot().y() ),
 
403
                                swap16IfLE( cur.width() ),
 
404
                                swap16IfLE( cur.height() )
 
405
                        } ;
 
406
 
 
407
                        const rfbFramebufferUpdateRectHeader rh =
 
408
                        {
 
409
                                rr,
 
410
                                swap32IfLE( rfbEncodingItalcCursor )
 
411
                        } ;
 
412
 
 
413
                        m_sock->write( (const char *) &rh, sizeof( rh ) );
 
414
 
 
415
                        QDataStream ds( m_sock );
 
416
                        ds << cur;
 
417
                }
 
418
 
 
419
                // reset vars
 
420
                //m_changedRegion.clear();
 
421
                m_changedRegion = QRegion();
 
422
                m_cursorShapeChanged = FALSE;
 
423
        }
 
424
        //m_sock->waitForBytesWritten();
 
425
        m_sock->flush();
 
426
 
 
427
        m_dataMutex.unlock();
 
428
        //QTimer::singleShot( 40, this, SLOT( processClient() ) );
 
429
}
 
430
 
 
431
 
 
432
 
 
433
 
 
434
void demoServerClient::run( void )
 
435
{
 
436
        QMutexLocker ml( &m_dataMutex );
 
437
 
 
438
        QTcpSocket sock;
 
439
        m_sock = &sock;
 
440
        if( !m_sock->setSocketDescriptor( m_socketDescriptor ) )
 
441
        {
 
442
                qCritical( "demoServerClient::run(): "
 
443
                                "could not set socket-descriptor - aborting" );
 
444
                deleteLater();
 
445
                return;
 
446
        }
 
447
 
 
448
        socketDevice sd( qtcpsocketDispatcher, m_sock );
 
449
        if( !isdServer::protocolInitialization( sd,
 
450
                                                ItalcAuthHostBased, TRUE ) )
 
451
        {
 
452
                qCritical( "demoServerClient:::run(): "
 
453
                                        "protocol initialization failed" );
 
454
                deleteLater();
 
455
                return;
 
456
        }
 
457
 
 
458
        rfbClientInitMsg ci;
 
459
 
 
460
        if( !sd.read( (char *) &ci, sizeof( ci ) ) )
 
461
        {
 
462
                deleteLater();
 
463
                return;
 
464
        }
 
465
 
 
466
        rfbServerInitMsg si = m_conn->m_si;
 
467
        si.framebufferWidth = swap16IfLE( si.framebufferWidth );
 
468
        si.framebufferHeight = swap16IfLE( si.framebufferHeight );
 
469
        si.format.redMax = swap16IfLE( si.format.redMax );
 
470
        si.format.greenMax = swap16IfLE( si.format.greenMax );
 
471
        si.format.blueMax = swap16IfLE( si.format.blueMax );
 
472
        si.nameLength = swap32IfLE( si.nameLength );
 
473
        si.format.bigEndian = ( QSysInfo::ByteOrder == QSysInfo::BigEndian )
 
474
                                                                        ? 1 : 0;
 
475
        if( !sd.write( ( const char *) &si, sizeof( si ) ) )
 
476
        {
 
477
                deleteLater();
 
478
                return;
 
479
        }
 
480
 
 
481
        char * desktop_name = new char[m_conn->m_si.nameLength+1];
 
482
        desktop_name[0] = 0;
 
483
 
 
484
        if( !sd.write( desktop_name, m_conn->m_si.nameLength ) )
 
485
        {
 
486
                deleteLater();
 
487
                return;
 
488
        }
 
489
 
 
490
        delete[] desktop_name;
 
491
 
 
492
 
 
493
        rfbSetPixelFormatMsg spf;
 
494
 
 
495
        if( !sd.read( (char *) &spf, sizeof( spf ) ) )
 
496
        {
 
497
                deleteLater();
 
498
                return;
 
499
        }
 
500
 
 
501
        // we have to do server-side endianess-conversion in case it differs
 
502
        // between client and server
 
503
        if( spf.format.bigEndian != si.format.bigEndian )
 
504
        {
 
505
                m_otherEndianess = TRUE;
 
506
        }
 
507
 
 
508
        char buf[sizeof( rfbSetPixelFormatMsg ) + MAX_ENCODINGS *
 
509
                                                        sizeof( Q_UINT32 )];
 
510
        rfbSetEncodingsMsg * se = (rfbSetEncodingsMsg *) buf;
 
511
 
 
512
        if( !sd.read( (char *) se, sizeof( *se ) ) )
 
513
        {
 
514
                deleteLater();
 
515
                return;
 
516
        }
 
517
        se->nEncodings = swap16IfLE( se->nEncodings );
 
518
 
 
519
        Q_UINT32 * encs = (Q_UINT32 *)( &buf[sizeof(rfbSetEncodingsMsg)] );
 
520
 
 
521
        if( !sd.read( (char *) encs, se->nEncodings * sizeof( Q_UINT32 ) ) )
 
522
        {
 
523
                deleteLater();
 
524
                return;
 
525
        }
 
526
 
 
527
        bool has_italc_encoding = FALSE;
 
528
        for( Q_UINT32 i = 0; i < se->nEncodings; ++i )
 
529
        {
 
530
                if( swap32IfLE( encs[i] ) == rfbEncodingItalc )
 
531
                {
 
532
                        has_italc_encoding = TRUE;
 
533
                }
 
534
        }
 
535
 
 
536
        if( !has_italc_encoding )
 
537
        {
 
538
                qCritical( "demoServerClient::run(): "
 
539
                                        "client has no italc-encoding" );
 
540
                deleteLater();
 
541
                return;
 
542
        }
 
543
 
 
544
        // for some reason we have to do this to make the following connection
 
545
        // working
 
546
 
 
547
        connect( m_conn, SIGNAL( cursorShapeChanged() ),
 
548
                                this, SLOT( updateCursorShape() ) );
 
549
        connect( m_conn, SIGNAL( regionUpdated( const QRegion & ) ),
 
550
                        this, SLOT( updateRegion( const QRegion & ) ) );
 
551
 
 
552
        ml.unlock();
 
553
 
 
554
        // first time send a key-frame
 
555
        updateRegion( m_conn->screen().rect() );
 
556
 
 
557
        //connect( m_sock, SIGNAL( readyRead() ), this, SLOT( processClient() ) );
 
558
        connect( m_sock, SIGNAL( disconnected() ), this,
 
559
                                                        SLOT( deleteLater() ) );
 
560
 
 
561
        QTimer t;
 
562
        connect( &t, SIGNAL( timeout() ), this, SLOT( moveCursor() ),
 
563
                                                        Qt::DirectConnection );
 
564
        t.start( CURSOR_UPDATE_TIME );
 
565
        QTimer t2;
 
566
        connect( &t2, SIGNAL( timeout() ), this, SLOT( processClient() ),
 
567
                                                        Qt::DirectConnection );
 
568
        t2.start( 50 );
 
569
        //moveCursor();
 
570
        //processClient();
 
571
        // now run our own event-loop for optimal scheduling
 
572
        exec();
 
573
}
 
574
 
 
575
 
 
576
 
 
577
#include "demo_server.moc"
 
578