summaryrefslogtreecommitdiffstats
path: root/src/serviceframework/ipc/qremoteserviceregister_s60.cpp
blob: ad0ecb7d26d5129a0e6d1afb3e18c1cd4cec0b3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qremoteserviceregister_s60_p.h"
#include "ipcendpoint_p.h"
#include "objectendpoint_p.h"
#include <QTimer>
#include <QCoreApplication>

#include <e32base.h>
#include <f32file.h>

//#define QT_SFW_SYMBIAN_IPC_DEBUG

/* IPC based on Symbian Client-Server framework
 * This module implements the Symbian specific IPC mechanisms and related control.
 * IPC is based on Symbian Client-Server architecture.
 */

QTM_BEGIN_NAMESPACE

#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
void printServicePackage(const QServicePackage& package)
{
  if(package.d) {
    qDebug() << "QServicePackage packageType  : " << package.d->packageType;
    qDebug() << "QServicePackage QUuid        : " << package.d->messageId;
    qDebug() << "QServicePackage responseType : " << package.d->responseType;
    qDebug() << "QServicePackage value        : " << package.d->payload;
  }
  else {
    qDebug() << "Invalid ServicePackage" << " LEAVING"; 
    User::Leave(KErrCorrupt);
  }
}
#endif

const TInt KSyncSemaphoreTimeout=1000000; //1 Sec 

class SymbianClientEndPoint: public QServiceIpcEndPoint
{
    Q_OBJECT
public:
    SymbianClientEndPoint(RServiceSession* session, QObject* parent = 0)
        : QServiceIpcEndPoint(parent), session(session)
    {
        Q_ASSERT(session);
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG        
        qDebug() << "Symbian IPC endpoint created. 255 buffer";
#endif
        connect(session, SIGNAL(Disconnected()), this, SIGNAL(disconnected()));
    }

    ~SymbianClientEndPoint()
    {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "Symbian IPC client endpoint destroyed.";
#endif
    }

    void PackageReceived(QServicePackage package)
    {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
        qDebug() << "SymbianClientEndPoint::PackageReceived. Enqueueing and emiting ReadyRead()";
        printServicePackage(package);
#endif
        incoming.enqueue(package);
        emit readyRead();
    }
    
protected:
    void flushPackage(const QServicePackage& package)
    {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
        qDebug() << "SymbianClientEndPoint::flushPackage() for package: ";
        printServicePackage(package);
#endif
        session->SendServicePackage(package);
    }

private:
    RServiceSession *session;
};

class SymbianServerEndPoint: public QServiceIpcEndPoint
{
    Q_OBJECT
public:
    SymbianServerEndPoint(CServiceProviderServerSession* session, QObject* parent = 0)
        : QServiceIpcEndPoint(parent), session(session), obj(0)
    {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
        qDebug() << "Symbian IPC server endpoint created.";
#endif
        Q_ASSERT(session);
        // CBase derived classes cannot inherit from QObject,
        // hence manual ownershipping instead of Qt hierarchy.
        session->SetParent(this);
    }


    ~SymbianServerEndPoint()
    {
    #ifdef QT_SFW_SYMBIAN_IPC_DEBUG
        qDebug() << "Symbian IPC server endpoint destroyed. --- emit disconnected";
    #endif

        emit disconnected();
    }

    void packageReceived(QServicePackage package)
    {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG      
        qDebug() << "SymbianServerEndPoint::packageReceived, putting to queue and emiting readyread.";
        printServicePackage(package);
#endif        
        incoming.enqueue(package);
        emit readyRead();
    }
#ifdef Q_OS_SYMBIAN
		void resetSession()
		{
			session=0;
		}
#endif //End Q_OS_SYMBIAN		
    void setObjectEndPoint(ObjectEndPoint *aObj)
    {
        obj = aObj;
#ifdef Q_OS_SYMBIAN
		    session->setObjEndpoint(obj);
#endif //End Q_OS_SYMBIAN
    }

protected:
    void flushPackage(const QServicePackage& package)
    {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
        qDebug() << "SymbianServerEndPoint::flushPackage() for package: ";
        printServicePackage(package);
#endif
#ifdef Q_OS_SYMBIAN
        if(!session)
           return;
#endif //End Q_OS_SYMBIAN

        TRAPD(err, session->SendServicePackageL(package));
        if(err != KErrNone){
            qDebug() << "flushPackage: Failed to send request: " << err;
        }
    }

private:
    CServiceProviderServerSession *session;
    ObjectEndPoint *obj;
};

QRemoteServiceRegisterSymbianPrivate::QRemoteServiceRegisterSymbianPrivate(QObject *parent)
    : QRemoteServiceRegisterPrivate(parent), m_server(0)
{
}

QRemoteServiceRegisterSymbianPrivate::~QRemoteServiceRegisterSymbianPrivate()
{
    delete m_server;
}

void QRemoteServiceRegisterSymbianPrivate::publishServices(const QString &ident)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG  
    qDebug() << "Start QRemoteServiceRegisterSymbianPrivate::publishServices: " << ident << this;
#endif
    // Create service side of the Symbian Client-Server architecture.
    m_server = new CServiceProviderServer(this);
    TPtrC serviceIdent(reinterpret_cast<const TUint16*>(ident.utf16()));

    if(getSecurityFilter())
      m_server->setSecurityFilter(getSecurityFilter());

    TInt err = m_server->Start(serviceIdent);
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG    
    if (err != KErrNone) {
        qDebug() << "publishServices: server->Start() failed: " << err;
    } else {
        qDebug("publishServices: service started successfully");
    }
#endif
    // If we're started by the client, notify them we're running
    RProcess::Rendezvous(KErrNone);
    
    //An attempt to fix Synchronization issues when Rendezvous() is already triggered
    //by creation of QApplication().
    RProcess thisProcess;
    TFileName fileName = thisProcess.FileName();
    TParse p;
    p.Set(fileName,NULL,NULL);
    
    /* Just try to Open the global semaphore. If for eg a UI service is started by other means
     * than a client connecting to it then there is no need to create the Semaphore.
     * (Also for services that are started by default at System startup.
     */
    RSemaphore syncSemaphore;
    TInt semErr = syncSemaphore.OpenGlobal(p.Name(),EOwnerThread);
    if(semErr == KErrNone)
        {
        syncSemaphore.Signal();
        }
    syncSemaphore.Close();
}

void QRemoteServiceRegisterSymbianPrivate::processIncoming(CServiceProviderServerSession* newSession)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG  
    qDebug("processingIncoming session creation.");
#endif
    // Create service provider-side endpoints.
    SymbianServerEndPoint* ipcEndPoint = new SymbianServerEndPoint(newSession, this);
    ObjectEndPoint* endPoint = new ObjectEndPoint(ObjectEndPoint::Service, ipcEndPoint, this);
    ipcEndPoint->setObjectEndPoint(endPoint);
}

QRemoteServiceRegister::SecurityFilter QRemoteServiceRegisterSymbianPrivate::setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter)
{
  if(m_server)
    m_server->setSecurityFilter(filter);

  return QRemoteServiceRegisterPrivate::setSecurityFilter(filter);
}


QRemoteServiceRegisterPrivate* QRemoteServiceRegisterPrivate::constructPrivateObject(QObject *parent)
{
  return new QRemoteServiceRegisterSymbianPrivate(parent);
}

QObject* QRemoteServiceRegisterPrivate::proxyForService(const QRemoteServiceRegister::Entry &entry, const QString &location)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << " Start QRemoteServiceRegisterPrivate::proxyForService: " << location;
#endif
    // Create client-side session for the IPC and connect it to the service
    // provide. If service provider is not up, it will be started.
    // Connecting is tried few times in a loop, because if service starting is
    // done at device startup, everything may not be ready yet.
    RServiceSession *session = new RServiceSession(location);
    int err = session->Connect();
#if 0
    int i = 0;
    while (err != KErrNone) {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG      
        qDebug() << "proxyForService Connecting in loop: " << i;
#endif        
        if (i > 10) {
            qWarning() << "QtSFW failed to connect to service provider.";
            return NULL;
        }
        User::After(50);
        err = session->Connect();
        i++;
    }
#endif
    //Connecting in loop is now done inside the Connect function.
    if(err != KErrNone){
        qWarning() << "QtSFW failed to connect to service provider.";
        return NULL;
    }

    // Create IPC endpoint. In practice binds the communication session and abstracting
    // class presenting the IPC endoint.
    SymbianClientEndPoint* ipcEndPoint = new SymbianClientEndPoint(session);
    ipcEndPoint->setParent(session);
    // Create an active message solicitor, which listens messages from server
    ServiceMessageListener* messageListener = new ServiceMessageListener(session, ipcEndPoint);    
    // Create object endpoint, which handles the metaobject protocol.
    ObjectEndPoint* endPoint = new ObjectEndPoint(ObjectEndPoint::Client, ipcEndPoint);
    endPoint->setParent(session);
    QObject *proxy = endPoint->constructProxy(entry);
    session->setParent(proxy);
    QObject::connect(session, SIGNAL(errorUnrecoverableIPCFault(QService::UnrecoverableIPCError)),
        proxy, SIGNAL(errorUnrecoverableIPCFault(QService::UnrecoverableIPCError)));
    return proxy;
}

RServiceSession::RServiceSession(QString address) 
: iSize(0), iListener(0), iDataSizes(KIpcBufferMinimumSize),iServerStarted(EFalse)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "RServiceSession() for address: " << address;
#endif
    qt_symbian_throwIfError(iMessageFromServer.Create(KIpcBufferMinimumSize));
    iServerAddress = address;
}

RServiceSession::~RServiceSession()
{
    delete iListener;
    Close();
    iMessageFromServer.Close();
}

void RServiceSession::setListener(ServiceMessageListener *listener)
{
  iListener = listener;
}

void RServiceSession::Close()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "RServiceSession close()";
#endif
    RSessionBase::Close();
}

TInt RServiceSession::Connect()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "RServiceSession Connect()";
#endif
    TInt err=KErrUnknown;
    if(!iServerStarted){
        TInt err = StartServer();
        if (err == KErrNone) {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
            qDebug() << "StartServer successful, Creating session.";
#endif
        iServerStarted = ETrue;
        }
    }
    TPtrC serviceAddressPtr(reinterpret_cast<const TUint16*>(iServerAddress.utf16()));

    for (int i = 0; (err != KErrNone) && (i < 1000); i++) {
        err = CreateSession(serviceAddressPtr, Version());
        if (err != KErrNone)
            User::After(1000);
    }
   
    return err;
}

TVersion RServiceSession::Version() const
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "RServiceSession Version()";
#endif
    return TVersion(KServerMajorVersionNumber, KServerMinorVersionNumber, KServerBuildVersionNumber);
}

void RServiceSession::SendServicePackage(const QServicePackage& aPackage)
{
    // Serialize the package into byte array, wrap it in descriptor,
    // and send to service provider.
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_6);
    out << aPackage;
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "SendServicePackage: Size of package sent from client to server: " << block.count();
#endif
    TPtrC8 ptr8((TUint8*)(block.constData()), block.size());
    TIpcArgs args(&ptr8, &iError);
    TInt err = SendReceive(EServicePackage, args);
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG    
    qDebug() << "SendServicePackage error code received: " << err;
#endif
    if(err != KErrNone){
      enum QService::UnrecoverableIPCError e  = QService::ErrorUnknown;
      switch(err){
      case KErrServerTerminated:
        e = QService::ErrorServiceNoLongerAvailable;
        break;
      case KErrNoMemory:
      case KErrServerBusy: // if the slots are full, something is really wrong        
        e = QService::ErrorOutofMemory;
        break;
      }
      emit errorUnrecoverableIPCFault(e);
    }
}

void RServiceSession::addDataSize(TInt dataSize)
{
    iDataSizes.addSample(dataSize);
}

TInt RServiceSession::doStartServer()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "RServiceSession::doStartServer()";
#endif
    TInt ret = KErrNone;
       
    TPtrC serviceAddressPtr(reinterpret_cast<const TUint16*>(iServerAddress.utf16()));
    
    TFindServer findServer(serviceAddressPtr);
    TFullName name;
    // Looks up from Kernel-side if there are active servers with the given name.
    // If not found, a process providing the service needs to be started.    
    if (findServer.Next(name) != KErrNone) {
#if defined(__WINS__) && !defined(SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD)
          qWarning("WINS Support for QSFW OOP not implemented.");
#else
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
        qDebug() << "RServiceSession::doStartServer() Service not found. Starting " << iServerAddress;
#endif
        RSemaphore syncSemaphore;
        TInt symErr = syncSemaphore.CreateGlobal(serviceAddressPtr,0,EOwnerThread);
        if(symErr!= KErrNone && symErr==KErrAlreadyExists){
            symErr =   syncSemaphore.OpenGlobal(serviceAddressPtr,EOwnerThread);
        }
        if(symErr != KErrNone) {
            return symErr;
        }
        
        TRequestStatus status;
        RProcess serviceServerProcess;
        ret = serviceServerProcess.Create(serviceAddressPtr, KNullDesC);
        if (ret != KErrNone) {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
            qDebug() << "doStartServer RProcess::Create failed: " << ret;
#endif
            syncSemaphore.Close();
            return ret;
        }
        // Point of synchronization. Waits until the started process calls
        // counterpart of this function (quits wait also if process dies / panics).
        serviceServerProcess.Rendezvous(status);

        if (status != KRequestPending) {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
            qDebug() << "doStartServer Service Server Process Rendezvous() failed, killing process.";
#endif
            serviceServerProcess.Kill(KErrNone);
            serviceServerProcess.Close();
            syncSemaphore.Close();
            return KErrGeneral;
        } else {
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG          
            qDebug() << "doStartServer Service Server Process Rendezvous() successful, resuming process.";
#endif
            serviceServerProcess.Resume();
        }
        User::WaitForRequest(status);
        if (status != KErrNone){
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
            qDebug("RTR Process Resume failed.");
#endif      
            syncSemaphore.Close();
            serviceServerProcess.Close();
            return status.Int();
        }
      
        //Wait for signal from Semaphore  
        //Should there be a timeout as well ?.
        TInt semRet = KErrNone;
        do{
            semRet = syncSemaphore.Wait(KSyncSemaphoreTimeout);
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG          
            qDebug() << "doStartServer: SyncSemaphore Wait() returned: "<< semRet;
#endif
           TFindServer findServer(serviceAddressPtr);
           if(findServer.Next(name)==KErrNone){
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG          
            qDebug() << "doStartServer: Found Published server ";
#endif
               break;
           }
        }while(semRet == KErrTimedOut && serviceServerProcess.ExitType() == EExitPending);
        
        if(serviceServerProcess.ExitType() != EExitPending){
            //Came out loop because server died
            ret = KErrGeneral;
        }
        
        // Free the handle to the process (RHandleBase function, does not 'close process')
        serviceServerProcess.Close();
        syncSemaphore.Close();
#endif // __WINS__
    } else {
        qDebug() << "RServiceSession::doStartServer() GTR Service found from Kernel, no need to start process.";
    }
    return ret;   
    
}

// StartServer() checks if the service is already published by someone (i.e. can be found
// from Kernel side). If not, it will start the process that provides the service.
TInt RServiceSession::StartServer()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "RServiceSession::StartServer()";
#endif
    TInt ret = KErrNone;
    
    QString clientMutexStr = iServerAddress + "_clientsem";
    TPtrC clientMutexPtr = reinterpret_cast<const TUint16*>(clientMutexStr.utf16());
    
    RMutex clientMutex;
    TInt mutexError = clientMutex.CreateGlobal(clientMutexPtr);
    if ( KErrAlreadyExists == mutexError ){
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "RServiceSession::StartServer() ClientMutex already exists. Trying to Open";
#endif
        mutexError = clientMutex.OpenGlobal( clientMutexPtr );
     }
    
    if(KErrNone != mutexError){
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "RServiceSession::StartServer() ClientMutex Couldnot be opened";
#endif
        return mutexError;
    }
    
    clientMutex.Wait();
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "RServiceSession::StartServer() ClientMutex Wait() over. Starting server";
#endif
    ret = doStartServer();
    
    clientMutex.Signal();
    clientMutex.Close();
    
    return ret;
}

/* Since the average size will not change in the middle of a fragmented message
 * trasnfer actual updates to buffer size will happen only when a new message
 * arrives */
void RServiceSession::updateIpcBufferSize()
{
   TInt weightedAvg = iDataSizes.averageWeighted();

#ifdef QT_SFW_SYMBIAN_IPC_DEBUG          
   qDebug() << "updateIpcBufferSize(): current weighted average of data size is: "<<weightedAvg;
   qDebug() << "Current IPC Buffer size is: "<<iMessageFromServer.MaxLength();
#endif
   TInt newSize = iMessageFromServer.MaxLength();
   if(weightedAvg > iMessageFromServer.MaxLength()){
       newSize = iMessageFromServer.MaxLength()*2;
   }
   else if(weightedAvg < iMessageFromServer.MaxLength()/2){

         newSize = iMessageFromServer.MaxLength()/2;
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG          
   qDebug() << "updateIpcBufferSize(): current weighted average of data size is:(2) "<<weightedAvg<<" max/2";
#endif
   }
   
   if(newSize < KIpcBufferMinimumSize)
       newSize = KIpcBufferMinimumSize;
   else if(newSize > KIpcBufferMaximumSize)
       newSize = KIpcBufferMaximumSize;


   if(newSize != iMessageFromServer.MaxLength()) {

        iMessageFromServer.SetLength(0);
        //If realloc fails the old descriptor is left unchanged.
        iMessageFromServer.ReAlloc(newSize); 
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG          
       qDebug() << "updateIpcBufferSize():  New Size of IPC Buffer: "<<newSize;
#endif
   }
}

void RServiceSession::ListenForPackages(TRequestStatus& aStatus)
{    
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "GTR RServiceSession::ListenForPackages(), iSize: " << iSize();
#endif
    updateIpcBufferSize();
    iArgs.Set(0, &iMessageFromServer);
    // Total Size of returned messaage,which might differ from the amount of data in iMessageFromServer
    iArgs.Set(1, &iSize); 
    iArgs.Set(2, &iError);
    
    SendReceive(EPackageRequest, iArgs, aStatus);
}

void RServiceSession::CancelListenForPackages()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG  
    qDebug("RServiceSession::CancelListenForPackages -- 2");
#endif
    TInt err = SendReceive(EPackageRequestCancel, TIpcArgs(NULL));
    if(err != KErrNone){
      enum QService::UnrecoverableIPCError e = QService::ErrorUnknown;
      switch(err){
      case KErrServerTerminated:        
        e = QService::ErrorServiceNoLongerAvailable;
        break;
      case KErrNoMemory:
      case KErrServerBusy: // if the slots are full, something is really wrong        
        e = QService::ErrorOutofMemory;
        break;
      }
      emit errorUnrecoverableIPCFault(e);
    }
}

void RServiceSession::ipcFailure(QService::UnrecoverableIPCError err)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG  
    qDebug("RServiceSession::ipcFailure ipc Fault reported");
#endif
  emit errorUnrecoverableIPCFault(err);
}

static const TUint myRangeCount = 1;
static const TInt myRanges[myRangeCount] =
    {
    0 //range is 0-Max inclusive
    };
static const TUint8 myElementsIndex[myRangeCount] =
    {
    CPolicyServer::EAlwaysPass
    };
static const CPolicyServer::TPolicyElement myElements[] =
    {
        {_INIT_SECURITY_POLICY_PASS } // Dummy entry
    };
static const CPolicyServer::TPolicy myPolicy =
    {
    CPolicyServer::ECustomCheck, //specifies all connect attempts should pass
    myRangeCount,
    myRanges,
    myElementsIndex,
    myElements,
    };

CServiceProviderServer::CServiceProviderServer(QRemoteServiceRegisterSymbianPrivate* aOwner)
    : CPolicyServer(EPriorityNormal, myPolicy), iSessionCount(0), iOwner(aOwner), iFilter(0)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug("CServiceProviderServer constructor");
#endif
    Q_ASSERT(aOwner);
}

CPolicyServer::TCustomResult CServiceProviderServer::CustomSecurityCheckL(const RMessage2 &aMessage, TInt &aAction, TSecurityInfo &aMissing)
{
    if(iFilter){
        if(iFilter(reinterpret_cast<const void *>(&aMessage))){
            return CPolicyServer::EPass;
        }
        else {
            return CPolicyServer::EFail;
        }
    }
    return CPolicyServer::EPass;
}

CSession2* CServiceProviderServer::NewSessionL(const TVersion &aVersion, const RMessage2 &aMessage) const
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "Start CServiceProviderServer::NewSessionL()" ;
#endif
    if (!User::QueryVersionSupported(TVersion(KServerMajorVersionNumber,
                                              KServerMinorVersionNumber, KServerBuildVersionNumber), aVersion))
    {
        User::Leave(KErrNotSupported);
    }
    CServiceProviderServerSession* session = CServiceProviderServerSession::NewL(*const_cast<CServiceProviderServer*>(this));
    iOwner->processIncoming(session);
    return session;
}

void CServiceProviderServer::IncreaseSessions()
{
    iSessionCount++;
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << ">>>> CServiceProviderServer incremented session count to: " << iSessionCount;
#endif
}

void CServiceProviderServer::DecreaseSessions()
{
    iSessionCount--;
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "<<<< CServiceProviderServer decremented session count to: " << iSessionCount;
#endif
    if(iSessionCount == 0){
        Cancel();
        if(iOwner->quitOnLastInstanceClosed())
          QCoreApplication::exit();
    }
}

void CServiceProviderServer::setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter)
{
  iFilter = filter;
}

CServiceProviderServerSession *CServiceProviderServerSession::NewL(CServiceProviderServer &aServer)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug("CServiceProviderServerSession::NewL()");
#endif
    CServiceProviderServerSession *self = CServiceProviderServerSession::NewLC(aServer);
    CleanupStack::Pop(self);
    return self;
}

CServiceProviderServerSession *CServiceProviderServerSession::NewLC(CServiceProviderServer &aServer)
{
    CServiceProviderServerSession* self = new (ELeave) CServiceProviderServerSession(aServer);
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
}

CServiceProviderServerSession::CServiceProviderServerSession(CServiceProviderServer &aServer)
    : iServer(aServer)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug("CServiceProviderServerSession constructor");
#endif
    iServer.IncreaseSessions();
}

void CServiceProviderServerSession::ConstructL()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug("OTR CServiceProviderServerSession::ConstructL()");
#endif
    iTotalSize = 0;    // No data
    iBlockData.clear();// clear the buffer
}

CServiceProviderServerSession::~CServiceProviderServerSession()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "CServiceProviderServerSession destructor";
#endif
    iServer.DecreaseSessions();
    delete iByteArray;
#ifdef Q_OS_SYMBIAN
	//Let the pending work get over...
	ObjectEndPointMonitor::MarkForDelete(iObjEndPoint);


  // The session is being deleted. Keep the IPC endpoint up-to-date
	iOwner->resetSession();
	
	// Is the ref count of the object endpoint 0? If so, delete the IPC endpoint. Otherwise,
	// do nothing...the object endpoint will be taken care by the monitor and since the 
	// IPC endpoint is a child of the object endpoint, it shall also be deleted subsequently
	if( (iObjEndPoint->getRefCount() & ~ObjectEndPoint::MarkedForDelete) == 0){
		qDebug() << "Delete server IPC endpoint";
		// Delete the IPC End point only if there is an activity on the Object endpoint
		delete iOwner;
	}
#else
    delete iOwner; 
#endif//End Q_OS_SYMBIAN
}

void CServiceProviderServerSession::ServiceL(const RMessage2 &aMessage)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "Start CServiceProviderServerSession::ServiceL for message: " << aMessage.Function() ;
#endif    
    switch (aMessage.Function()) 
    {
    case EServicePackage:
        HandleServicePackageL(aMessage);
        aMessage.Complete(KErrNone);
        break;
    case EPackageRequest:
        HandlePackageRequestL(aMessage);
        break;
    case EPackageRequestCancel:
        HandlePackageRequestCancelL(aMessage);
        break;
    }
}

void CServiceProviderServerSession::HandleServicePackageL(const RMessage2& aMessage)
{
    // Reproduce the serialized data.
    HBufC8* servicePackageBuf8 = HBufC8::New(aMessage.GetDesLength(0));
    if (!servicePackageBuf8) {
        User::Leave( KErrNoMemory );
    }

    TPtr8 ptrToBuf(servicePackageBuf8->Des());
    TInt ret = KErrNone;
    TRAP(ret, aMessage.ReadL(0, ptrToBuf));
    if (ret != KErrNone) {
        // TODO: is this error handleing correct
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG      
        qDebug() << "HandleServicePackageL. Message read failed: " << ret;
#endif
        //iDb->lastError().setError(DBError::UnknownError);
        //aMessage.Write(1, LastErrorCode());
        delete servicePackageBuf8;
        User::Leave( ret );
    }

    QByteArray byteArray((const char*)ptrToBuf.Ptr(), ptrToBuf.Length());
    QDataStream in(byteArray);
    QServicePackage results;
    in >> results;

#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "CServiceProviderServerSession Reproduced service package: ";
    printServicePackage(results);
#endif
    iOwner->packageReceived(results);
    delete servicePackageBuf8;
}

void CServiceProviderServerSession::SetParent(SymbianServerEndPoint *aOwner)
{
    iOwner = aOwner;
}
#ifdef Q_OS_SYMBIAN
void CServiceProviderServerSession::setObjEndpoint(ObjectEndPoint* aObjEndpoint)
{
	iObjEndPoint = aObjEndpoint;
}
#endif //End Q_OS_SYMBIAN

void CServiceProviderServerSession::HandlePackageRequestL(const RMessage2& aMessage)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "HandlePackageRequestL(). Setting pending true and storing message." ;
#endif
    iMsg = aMessage;
    iPendingPackageRequest = ETrue;
    if(!iPendingPackageQueue.isEmpty())
      SendServicePackageL(iPendingPackageQueue.dequeue());
}

void CServiceProviderServerSession::HandlePackageRequestCancelL(const RMessage2& aMessage)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "HandlePackageRequestCancelL" ;
#endif
    if (iPendingPackageRequest) {
        iMsg.Complete(KErrCancel);
        iPendingPackageRequest = EFalse;
    }
    aMessage.Complete(EPackageRequestComplete);
}

void CServiceProviderServerSession::SendServicePackageL(const QServicePackage& aPackage)
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "CServiceProviderServerSession:: SendServicePackage for package: ";
    printServicePackage(aPackage);
#endif
    if (iPendingPackageRequest) {
        if(iBlockData.isEmpty()){
          // Serialize the package        
          QDataStream out(&iBlockData, QIODevice::WriteOnly);
          out.setVersion(QDataStream::Qt_4_6);
          out << aPackage;
          iTotalSize = iBlockData.size();
        }
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
        qDebug() << "Size of package sent from server to client: " << iBlockData.count();               
        qDebug() << "Size of buffer from client: " << iMsg.GetDesMaxLength(0);
#endif
        
        int size = iBlockData.size();
        if(size > iMsg.GetDesMaxLength(0)){
          size = iMsg.GetDesMaxLength(0);
          // enequeue the package so we send the  next chunk
          // when the next request comes through
          iPendingPackageQueue.prepend(aPackage); 
        }
        TPtrC8 ptr8((TUint8*)(iBlockData.constData()), size);      
        iMsg.WriteL(0, ptr8);
        iBlockData.remove(0, size);
//#ifdef QT_SFW_SYMBIAN_IPC_DEBUG        
//        if(status == KErrOverflow){
//          qDebug() << "OTR Server to client, got overflow, sending 0 bytes";
//        }
//        else if(status != KErrNone){
//          qDebug() << "OTR SendServicePackage: error code from send: " << status;
//        }
//#endif
        TPckgBuf<TInt> totalSize(iTotalSize);
        iMsg.WriteL(1,totalSize);                
        iMsg.Complete(EPackageRequestComplete);
        iPendingPackageRequest = EFalse;
    } else {
        iPendingPackageQueue.enqueue(aPackage);
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG        
        qWarning() << "RTR SendServicePackage: service package from server to client queued - no pending receive request.";
#endif
    }
}

ServiceMessageListener::ServiceMessageListener(RServiceSession* aSession, SymbianClientEndPoint* aOwner)
    : CActive(EPriorityNormal),
    iClientSession(aSession),
    iOwnerEndPoint(aOwner)
{
    Q_ASSERT(iClientSession);
    Q_ASSERT(iOwnerEndPoint);
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG    
    qDebug("ServiceMessageListener constructor");
#endif
    aSession->setListener(this);
    CActiveScheduler::Add(this);
    StartListening();
}

ServiceMessageListener::~ServiceMessageListener()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "ServiceMessageListener destructor";
#endif
    Cancel();
}

void ServiceMessageListener::StartListening()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "ServiceMessageListener::StartListening";
#endif
    iClientSession->ListenForPackages(iStatus);
    SetActive();
}

void ServiceMessageListener::DoCancel()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG  
    qDebug() << "ServiceMessageListener::DoCancel ";
#endif
    iClientSession->CancelListenForPackages();
}

void ServiceMessageListener::RunL()
{
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
    qDebug() << "ServiceMessageListener::RunL for iStatus.Int(should be 4): " << iStatus.Int();
#endif
    if (iStatus.Int() == EPackageRequestComplete) {
        // Client side has received a service package from server. Pass it onwards and
        // issue new pending request.
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
        qDebug() << "RunL length of the package received client side is: " << iClientSession->iMessageFromServer.Length();
#endif
        if(iClientSession->iMessageFromServer.Length() == 0){
          // we received 0 bytes from the other side, 
          // normally because it tried to write more bytes 
          // than were in the TDes
          User::Leave(KErrTooBig); 
        }

        if(!iByteArray.length()){
            /* Helps client session to calculate an optimum IPC buffer size */
            iClientSession->addDataSize(iClientSession->iSize());
        }
                
        iByteArray.append((const char*)iClientSession->iMessageFromServer.Ptr(),
                             iClientSession->iMessageFromServer.Length());
        if(iByteArray.length() >= iClientSession->iSize()){        
          QDataStream in(iByteArray);
          iByteArray.clear();
          QServicePackage results;
          in >> results;
#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
          qDebug() << "ServiceMessageListener Reproduced service package: ";
          printServicePackage(results);
#endif
          iOwnerEndPoint->PackageReceived(results);
        }          
        StartListening();
    }
    else if(iStatus.Int() < 0){
      TInt s = iStatus.Int();
      switch(s){
      case KErrServerTerminated:
        iClientSession->ipcFailure(QService::ErrorServiceNoLongerAvailable);
        break;
      case KErrServerBusy:
      case KErrNoMemory:
        iClientSession->ipcFailure(QService::ErrorOutofMemory);
        break;
      }
    }
}

#include "moc_qremoteserviceregister_s60_p.cpp"
#include "qremoteserviceregister_s60.moc"
QTM_END_NAMESPACE