bluetoothengine/headsetsimulator/core/src/RemoteControl/hsremotecontrolserver.cpp
author michal.sulewski
Wed, 15 Sep 2010 15:59:44 +0200
branchheadsetsimulator
changeset 60 90dbfc0435e3
permissions -rw-r--r--
source code commit

/*
 * Component Name: Headset Simulator
 * Author: Comarch S.A.
 * Version: 1.0
 * Copyright (c) 2010 Comarch S.A.
 *  
 * This Software is submitted by Comarch S.A. to Symbian Foundation Limited on 
 * the basis of the Member Contribution Agreement entered between Comarch S.A. 
 * and Symbian Foundation Limited on 5th June 2009 (“Agreement”) and may be 
 * used only in accordance with the terms and conditions of the Agreement. 
 * Any other usage, duplication or redistribution of this Software is not 
 * allowed without written permission of Comarch S.A.
 * 
 */
#include "hsremotecontrolserver.h"
#include "hscore.h" 
#include "hsremotecontroldatahandler.h"
#include "hsremotecontroltools.h"
#include "debug.h"

_LIT8(KHsATVGS,"AT+VGS=");
_LIT8(KHsATCommandEnding,"\r\n");
_LIT8(KHsATVGM,"AT+VGM=");

CHsControlServer* CHsControlServer::NewL( RSocketServ& aSocketServ,
        CHsCore* aHsCore )
    {
    CHsControlServer* self = CHsControlServer::NewLC( aSocketServ, aHsCore );
    CleanupStack::Pop( self );
    return self;
    }

CHsControlServer* CHsControlServer::NewLC( RSocketServ& aSocketServ,
        CHsCore* aHsCore )
    {
    CHsControlServer* self = new ( ELeave ) CHsControlServer( aSocketServ,
            aHsCore );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

CHsControlServer::CHsControlServer( RSocketServ& aSocketServ, CHsCore* aHsCore ) :
    iState( ENone ), iSocketServ( aSocketServ ), iHsCore( aHsCore )
    {
    }

void CHsControlServer::ConstructL()
    {
    iDataHandler = CHsRemoteControlDataHandler::NewL();
    }

CHsControlServer::~CHsControlServer()
    {
    TRACE_FUNC_ENTRY
    CancelListen();
    if ( iSocket )
        {
        delete iSocket;
        }
    if ( iListenSocket )
        {
        delete iListenSocket;
        }
    if ( iDataHandler )
        {
        delete iDataHandler;
        }

    TRACE_FUNC_EXIT
    }

void CHsControlServer::StartRemoteControlServerL()
    {
    TRACE_FUNC_ENTRY

    if ( iState != ENone )
        {
        TRACE_INFO (_L("ControlServer is already listening"))
        TRACE_FUNC_EXIT
        User::Leave( KErrInUse );
        }

    iState = EConnecting;
    TProtocolDesc ProtocolDesc;
    User::LeaveIfError( iSocketServ.FindProtocol( KHsRFComm(), ProtocolDesc ) );

    if ( iListenSocket )
        {
        // Return value may be ignored
        iListenSocket->Shutdown( RSocket::EImmediate );
        delete iListenSocket;
        iListenSocket = NULL;
        }
    iListenSocket = CBluetoothSocket::NewL( *this, iSocketServ,
            ProtocolDesc.iSockType, ProtocolDesc.iProtocol );

    User::LeaveIfError( iListenSocket->GetOpt(
            KRFCOMMGetAvailableServerChannel, KSolBtRFCOMM, iServerPort ) );

    TBTSockAddr btSockAddr;
    btSockAddr.SetPort( iServerPort );

    RegisterSdpL( iServerPort );
    User::LeaveIfError( iListenSocket->Bind( btSockAddr ) );

    TRACE_INFO( ( _L("Control Server port =  %d"), iServerPort) )
    User::LeaveIfError( iListenSocket->Listen( KHsSizeOfListenQueue ) );

    TBTServiceSecurity secSettings;
    TUid settingsUID = TUid::Uid( (TInt) KHsRemoteControlServiceID );
    secSettings.SetUid( settingsUID );
    secSettings.SetAuthentication( EFalse );
    secSettings.SetAuthorisation( EFalse );
    secSettings.SetEncryption( EFalse );

    btSockAddr.SetSecurity( secSettings );

    if ( iSocket )
        {
        // Return value may be ignored
        iSocket->Shutdown( RSocket::EImmediate );
        delete iSocket;
        iSocket = NULL;
        }
    iSocket = CBluetoothSocket::NewL( *this, iSocketServ );
    User::LeaveIfError( iListenSocket->Accept( *iSocket ) );
    iInitialized = ETrue;
    TRACE_INFO( _L("CHSControlServer::Listen() status = OK" ) )

    TRACE_FUNC_EXIT
    }

void CHsControlServer::CancelListen()
    {
    TRACE_FUNC_ENTRY
   
    if ( iState == EWaiting )//Client is connected to socket
        {
        iSocket->CancelAll();
        // Return value may be ignored
        iSocket->Shutdown( RSocket::EImmediate );
        delete iSocket;
        iSocket = NULL;
        iListenSocket->CancelAll();

        // Return value may be ignored
        iListenSocket->Shutdown( RSocket::EImmediate );
        delete iListenSocket;
        iListenSocket = NULL;
        }
    else
        { //Sockets are ready, but client is not connected
        delete iSocket;
        iSocket = NULL;
        delete iListenSocket;
        iListenSocket = NULL;
        }

    DeleteRecordSdp();

    iInitialized = EFalse;
    iState = ENone;

    TRACE_FUNC_EXIT
    }

void CHsControlServer::SetConnectionObserver(
        MRemoteControllerConnectionObserver &aRemoteControllerObserver )
    {
    iConnectionObserver = &aRemoteControllerObserver;
    }

void CHsControlServer::HandleConnectCompleteL( TInt aErr )
    {
    TRACE_FUNC_ENTRY
    TRACE_INFO( ( _L("aErr = %d"), aErr) );
    TRACE_FUNC_EXIT
    }

void CHsControlServer::HandleAcceptCompleteL( TInt aErr )
    {
    TRACE_FUNC_ENTRY
    TRACE_INFO( ( _L("aErr = %d"), aErr) );
    iState = EWaiting;
    Receive();
    if ( iConnectionObserver )
        {
        iConnectionObserver->HandleRemoteControllerConnected( aErr );
        }
    TRACE_FUNC_EXIT
    }

void CHsControlServer::HandleShutdownCompleteL( TInt aErr )
    {
    TRACE_FUNC_ENTRY
    TRACE_INFO( ( _L("aErr = %d"), aErr) );
    TRACE_FUNC_EXIT
    }

void CHsControlServer::HandleSendCompleteL( TInt aErr )
    {
    TRACE_FUNC_ENTRY

    TRACE_INFO( ( _L8("ControlServer sent %d bytes of data: [%S] with err [%d]")
            ,iSendDataBuffer.Length(), &iSendDataBuffer, aErr) )
    
    TInt error = KErrNone;

    if ( aErr == KErrNone )
        {
        iSendDataBuffer.Zero();
        if ( iTempDataBuffer.Length() > 0 )
            {
            iSendDataBuffer.Append( iTempDataBuffer );
            iTempDataBuffer.Zero();
            error = iSocket->Write( iSendDataBuffer );
            }
        }
    Receive();

    User::LeaveIfError( error );

    TRACE_FUNC_EXIT
    }

void CHsControlServer::HandleReceiveCompleteL( TInt aErr )
    {
    TRACE_FUNC_ENTRY
    TRACE_INFO( ( _L8("[ControlServer] received %d bytes of data: [%S]"
            "with err [%d]"), iReceiveDataBuffer.Length(), &iReceiveDataBuffer,
            aErr) )

    if ( aErr == KErrNone )
        {
        TInt error = KErrNone;

        if ( iSendDataBuffer.Length() > 0 )
            {
            error = iSocket->Write( iSendDataBuffer );
            }
        else if ( iTempDataBuffer.Length() > 0 )
            {
            iSendDataBuffer.Append( iTempDataBuffer );
            iTempDataBuffer.Zero();
            error = iSocket->Write( iSendDataBuffer );
            }

        TRAP_IGNORE( HandleRequestL( iReceiveDataBuffer ) );

        Receive();

        User::LeaveIfError( error );
        }
    else
        {
        TRACE_INFO( _L("ControlClient is disconnected") )

        if ( iConnectionObserver )
            {
            iConnectionObserver->HandleRemoteControllerDisconnected( aErr );
            }
        CancelListen();
        StartRemoteControlServerL();
        }
    TRACE_FUNC_EXIT
    }

void CHsControlServer::HandleIoctlCompleteL( TInt /*aErr*/)
    {
    TRACE_FUNC_ENTRY
    TRACE_FUNC_EXIT
    }

void CHsControlServer::HandleActivateBasebandEventNotifierCompleteL(
        TInt /*aErr*/, TBTBasebandEventNotification& /*aEventNotification*/)
    {
    TRACE_FUNC_ENTRY
    TRACE_FUNC_EXIT
    }

TInt CHsControlServer::Send( const TDesC8& aData )
    {
    TRACE_FUNC_ENTRY
    TInt error = KErrNone;
    if ( iState != EWaiting )
        {
        error = KErrNotReady;
        TRACE_INFO( _L("ControlServer not ready") )

        return error;
        }

    if ( iSendDataBuffer.Length() == 0 )
        {
        iSendDataBuffer.Append( iTempDataBuffer );
        iTempDataBuffer.Zero();
        iSendDataBuffer.Append( aData );
        }
    else
        {
        iTempDataBuffer.Append( aData );
        }

    if ( iSendDataBuffer.Length() > 0 )
        {
        iSocket->CancelRecv();
        error = iSocket->Write( iSendDataBuffer );
        Receive();
        }
    else
        {
        Receive();
        }
    TRACE_FUNC_EXIT
    return error;
    }

void CHsControlServer::Receive()
    {
    TRACE_FUNC_ENTRY
    // Return value may be ignored, 
    // error will be notified to HandleReceiveCompleteL
    iSocket->RecvOneOrMore( iReceiveDataBuffer, 0, iDataLength );
    TRACE_FUNC_EXIT
    }

void CHsControlServer::RegisterSdpL( TInt aChannel )
    {
    TRACE_FUNC_ENTRY

    User::LeaveIfError( iSdpServer.Connect() );
    User::LeaveIfError( iSdpDB.Open( iSdpServer ) );

    TUUID serviceUUID( KHsRemoteControlServiceID );
    iSdpDB.CreateServiceRecordL( serviceUUID, iSdpRecordHandle );

    CSdpAttrValueDES* valDES = CSdpAttrValueDES::NewDESL( NULL );
    CleanupStack::PushL( valDES );
    valDES->StartListL()->BuildDESL()->StartListL()->BuildUUIDL( TUUID(
            KL2CAPUUID ) )->EndListL()->BuildDESL()->StartListL()->BuildUUIDL(
            TUUID( KRFCommUUID ) )->BuildUintL(
            TSdpIntBuf <TUint8> ( aChannel ) )->EndListL()->EndListL();
    
    iSdpDB.UpdateAttributeL( iSdpRecordHandle,
            KSdpAttrIdProtocolDescriptorList, *valDES );
    
    CleanupStack::PopAndDestroy( valDES );

    iSdpDB.UpdateAttributeL( iSdpRecordHandle, KSdpAttrIdBasePrimaryLanguage
            + KSdpAttrIdOffsetServiceName, KServiceName );
    
    iSdpDB.UpdateAttributeL( iSdpRecordHandle, KSdpAttrIdBasePrimaryLanguage
            + KSdpAttrIdOffsetServiceDescription, KServiceDesc );
    
    UpdateAvailabilityL( ETrue );
    
    TRACE_INFO ( _L("CHsControlServer::RegisterSdpL, status = OK") )
    TRACE_FUNC_EXIT
    }

void CHsControlServer::UpdateAvailabilityL( TBool aAvailable )
    {
    TInt state = ( aAvailable ? KServicAvailable : KServiceUnavailable );
    // Set availability
    iSdpDB.UpdateAttributeL( iSdpRecordHandle, KSdpAttrIdServiceAvailability,
            state );
    // Mark record changed
    iSdpDB.UpdateAttributeL( iSdpRecordHandle, KSdpAttrIdServiceRecordState,
            ++iRecordState );
    }

void CHsControlServer::DeleteRecordSdp()
    {
    TRACE_FUNC_ENTRY

    iSdpDB.DeleteRecord( iSdpRecordHandle );
    iSdpRecordHandle = 0;
    iSdpDB.Close();
    iSdpServer.Close();

    TRACE_FUNC_EXIT
    }

void CHsControlServer::HandleRequestL( TDes8 &aRequest )
    {
    TRACE_FUNC_ENTRY

    TBuf8 <KHsRemoteControlPackageLength> buf;

    THsControlCommandData dummyBuf( KNullDesC8 );
    THsRemoteControlCommand command( dummyBuf, EHsLast );
    if ( iDataHandler )
        {
        TInt err = iDataHandler->RecognizeCommand( aRequest, command );
        if ( KErrNone != err )
            {
            User::Leave( KErrArgument );
            }
        }

    THsRemoteControlCommandType type = EHsLast;
    command.GetType( type );

    switch ( type )
        {
        case EHsTurnOn:
            {
            command.GetData( buf );

            RBuf8 cod;
            RBuf8 sdp;
            RBuf8 plugin;

            cod.CleanupClosePushL();
            sdp.CleanupClosePushL();
            plugin.CleanupClosePushL();

            RetrieveStartupParamsL( buf, cod, sdp, plugin );

            iHsCore->StartSimulationL( cod, sdp, plugin );

            CleanupStack::PopAndDestroy( 3 );
            }
            break;

        case EHsTurnOff:
            {
            iHsCore->StopSimulation();
            }
            break;
        case EHsConnectLastconnected:
            {
            iHsCore->ConnectWithLastConnectedL();
            }
            break;
        case EHsConnectDevAddress:
            {
            command.GetData( buf );
            iHsCore->ConnectWithDevAddress( buf.Expand() );
            }
            break;
        case EHsConnectName:
            {
            command.GetData( buf );
            iHsCore->ConnectWithName( buf.Expand() );
            }
            break;
        case EHsDisconnectAGs:
            {
            iHsCore->DisconnectClients();
            }
            break;
        case EHsAcceptCall:
            {
            User::LeaveIfError( iHsCore->AcceptIncomingCall() );
            }
            break;
        case EHsReleaseCall:
            {
            User::LeaveIfError( iHsCore->ReleaseOngoingCall() );
            }
            break;

        case EHsSetSpeakerVolume:
            {
            command.GetData( buf );
            RBuf8 tempBuf;
            tempBuf.CreateL( buf.Length() + KHsATCommandEnding().Length()
                    + KHsATVGS().Length() );
            tempBuf.Copy( KHsATVGS );
            tempBuf.Append( buf );
            tempBuf.Append( KHsATCommandEnding );

            iHsCore->Send( tempBuf );
            tempBuf.Close();

            }
            break;
        case EHsSetMicVolume:
            {
            command.GetData( buf );
            RBuf8 tempBuf;
            tempBuf.CreateL( buf.Length() + KHsATCommandEnding().Length()
                    + KHsATVGM().Length() );
            tempBuf.Copy( KHsATVGM );
            tempBuf.Append( buf );
            tempBuf.Append( KHsATCommandEnding );

            iHsCore->Send( tempBuf );
            tempBuf.Close();
            }
            break;
        case EHsSendAnyAt:
            {
            command.GetData( buf );
            User::LeaveIfError( iHsCore->Send( buf ) );
            }
            break;
        default:
            User::Leave( KErrArgument );

        }
    TRACE_FUNC_EXIT
    }

void CHsControlServer::RetrieveStartupParamsL( const TDesC8& aParams,
        RBuf8& aPluginCod, RBuf8& aPluginSdp, RBuf8& aPluginProfile )

    {
    TRACE_FUNC_ENTRY

    TInt sepPos = aParams.Find( KHsRemoteRequestParamSeparator );

    User::LeaveIfError( sepPos );

    aPluginCod.CreateL( aParams.Left( sepPos ) );

    sepPos += 2;

    TInt sepPos2 = aParams.Mid( sepPos, aParams.Length() - sepPos ).Find(
            KHsRemoteRequestParamSeparator );

    User::LeaveIfError( sepPos2 );

    aPluginSdp.CreateL( aParams.Mid( sepPos, sepPos2 ) );

    sepPos += 2;
    sepPos += sepPos2;

    aPluginProfile.CreateL( aParams.Mid( sepPos, aParams.Length() - sepPos ) );

    TRACE_FUNC_EXIT
    }