--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecmgmt/ucc/Source/MobileTermination/CPhone.cpp Mon Mar 08 15:04:18 2010 +0800
@@ -0,0 +1,593 @@
+/*
+* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+* Switches
+* System Includes
+*
+*/
+
+
+
+#include <stdio.h>
+#include <assert.h>
+#ifndef WIN32
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+#else
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+/*******************************************************************************
+ *
+ * Local Includes
+ *
+ ******************************************************************************/
+#include "CPhone.h"
+
+/*******************************************************************************
+ *
+ * Definitions
+ *
+ ******************************************************************************/
+#define POLLINTERVAL 1000
+
+#define CLEANUP_SOURCE_AIR_INTERFACE_START_FAILED 1
+#define CLEANUP_SOURCE_TE_CHANNEL_START_FAILED 2
+#define CLEANUP_SOURCE_INTERNAL_RUN_PHONE 3
+#define CLEANUP_SOURCE_MAIN_START_FAILED 4
+
+
+/*******************************************************************************
+ *
+ * Macro Functions
+ *
+ ******************************************************************************/
+#ifndef WIN32
+#define closesocket(x) (shutdown(x,SHUT_RDWR),close(x))
+#endif
+
+/*******************************************************************************
+ *
+ * Macro functions
+ *
+ ******************************************************************************/
+#ifndef WIN32
+#define Sleep(x) sleep(x/1000)
+#endif
+
+/*******************************************************************************
+ *
+ * Prototypes
+ *
+ ******************************************************************************/
+
+
+/*******************************************************************************
+ *
+ * Construction
+ *
+ ******************************************************************************/
+CPhone::CPhone() : iUdpAirInterface(&iPhoneData,&iLog), iTcpTeChannel(&iPhoneData,&iLog), iFilterPpp(&iPhoneData,&iLog), iMainThread("MainThread"), iAirInterfaceThread("AirInterfaceThread"), iTEChannelThread("TeChannelThread")
+{
+ // just need to set all the pointers to null
+ iFilter = NULL;
+ iDatalinkPacketise = NULL;
+ iDatalinkNull = NULL;
+ iProcessData = NULL;
+ iExitFlag = 0;
+ iStatus = MTS_INIT;
+
+ // clear the phone state
+ memset( &iPhoneData, 0, sizeof(iPhoneData) );
+}
+
+CPhone::~CPhone()
+{
+ // just need to check that all the pointers are freed
+ assert( iFilter == NULL );
+ assert( iDatalinkPacketise == NULL );
+ assert( iDatalinkNull == NULL );
+ assert( iProcessData == NULL );
+ assert( iStatus != MTS_RUNNING );
+}
+
+
+/*******************************************************************************
+ *
+ * PRIVATE METHOD: MAIN-THREAD: InternalInitialisePhone - setup everything - if
+ * this returns an error all resource MUST be cleaned up.
+ *
+ ******************************************************************************/
+MTError CPhone::InternalInitialisePhone( int aPhoneID, int aDatalinkConfig, int aFilterConfig, int *aErrCode )
+{
+ MTError merr;
+ TThreadError terr;
+
+ // check the params
+ assert( aPhoneID >= 0 );
+ assert( aErrCode != NULL );
+
+ // init the errors
+ *aErrCode = 0;
+
+ // setup the phone state
+ iPhoneData.iPhoneID = aPhoneID;
+
+ // create the appropriate filters
+ merr = CreateFilters( aFilterConfig );
+ if( merr != MTL_SUCCESS ) {
+ return merr;
+ }
+
+ // create the data link object
+ merr = CreateDatalinkLayer( aDatalinkConfig );
+ if( merr != MTL_SUCCESS ) {
+ DeleteFilters();
+ return merr;
+ }
+
+ // give the datalink object pointers to the air interface and the uu interface
+ iProcessData->SetAirInterface( &iUdpAirInterface );
+ iProcessData->SetTEChannel( &iTcpTeChannel );
+
+ // give each channel a pointer to the datalink
+ iUdpAirInterface.SetDatalink( iProcessData );
+ iTcpTeChannel.SetDatalink( iProcessData );
+ iUdpAirInterface.SetFilter( iFilter );
+ iTcpTeChannel.SetFilter( iFilter );
+
+ // create a thread for the air interface to listen
+ terr = iAirInterfaceThread.StartThread( (void*)AirInterfaceThreadProc, this, aErrCode );
+ if( terr != TE_NONE ) {
+ CleanupState( CLEANUP_SOURCE_AIR_INTERFACE_START_FAILED );
+ return MTL_FAILED_TO_CREATE_AIR_INTERFACE_THREAD;
+ }
+
+ // create a thread for the te channel to listen
+ terr = iTEChannelThread.StartThread( (void*)TEChannelThreadProc, this, aErrCode );
+ if( terr != TE_NONE ) {
+ CleanupState( CLEANUP_SOURCE_TE_CHANNEL_START_FAILED );
+ return MTL_FAILED_TO_CREATE_TE_CHANNEL_THREAD;
+ }
+
+ // cool, we are setup and ready to go
+ return MTL_SUCCESS;
+}
+
+
+/*******************************************************************************
+ *
+ * PRIVATE METHOD: MAIN-THREAD: InternalRunPhone - the main execution loop for
+ * the main thread of the phone - if this returns error then it MUST be cleaned
+ * up.
+ *
+ ******************************************************************************/
+MTError CPhone::InternalRunPhone( int *aErrCode )
+{
+ TThreadError terr;
+
+ // wait for the threads to complete or for a command to stop them
+ while( 1 ) {
+
+ // perform checks every X milliseconds
+ Sleep( POLLINTERVAL );
+
+ // check the state of the air_interface thread
+ terr = iAirInterfaceThread.WaitForThread( 0 );
+ if( terr == TE_NONE ) {
+ break;
+ }
+ assert( terr == TE_TIMEOUT );
+
+ // check the state of the channel thread
+ terr = iTEChannelThread.WaitForThread( 0 );
+ if( terr == TE_NONE ) {
+ break;
+ }
+ assert( terr == TE_TIMEOUT );
+
+ // check whether the external program has requested that we shutdown
+ if( iExitFlag != 0 ) {
+ break;
+ }
+ }
+
+ // cleanup everything
+ CleanupState( CLEANUP_SOURCE_INTERNAL_RUN_PHONE );
+
+ // done
+ return MTL_SUCCESS;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD: StartPhone - this wraps up init phone and run phone
+ *
+ ******************************************************************************/
+MTError CPhone::StartPhone( int aPhoneID, int aDatalinkConfig, int aFilterConfig, int *aErrCode )
+{
+ MTError merr;
+ TThreadError terr;
+
+ // check params
+ assert( aErrCode != NULL );
+ *aErrCode = 0;
+
+ // check the state
+ if( iStatus != MTS_INIT ) {
+ return MTL_INVALID_STATE;
+ }
+
+ // initialise all the sub-components
+ merr = InternalInitialisePhone( aPhoneID, aDatalinkConfig, aFilterConfig, aErrCode );
+ if( merr != 0 ) {
+ return merr;
+ }
+
+ // set the state
+ iStatus = MTS_RUNNING;
+
+ // start up a new thread that calls InternalRunPhone
+ terr = iMainThread.StartThread( (void*)MainThreadProc, this, aErrCode );
+ if( terr != TE_NONE ) {
+ CleanupState( CLEANUP_SOURCE_MAIN_START_FAILED );
+ return MTL_FAILED_TO_CREATE_MAIN_THREAD;
+ }
+
+ // ok everything is running -- return ok
+ return MTL_SUCCESS;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD: StopPhone - signal the main handler to stop
+ * everything
+ *
+ ******************************************************************************/
+MTError CPhone::StopPhone()
+{
+ MTStatus mstatus;
+
+ // set the exit flag
+ iExitFlag = 1;
+
+ // depends on our state
+ switch( iStatus ) {
+ case MTS_INIT:
+ return MTL_SUCCESS;
+
+ case MTS_RUNNING:
+ case MTS_SHUTDOWN_ALL_BUT_MAIN:
+
+ while( 1 ) {
+ mstatus = GetStatus();
+ if( mstatus == MTS_SHUTDOWN_ALL ) {
+ return MTL_SUCCESS;
+ }
+ Sleep( 500 );
+ }
+ break;
+
+ case MTS_SHUTDOWN_ALL:
+ return MTL_SUCCESS;
+ }
+
+ // should never get here
+ assert( !"INVALID CODE PATH" );
+ return MTL_SUCCESS;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD: Sets the remote address for the uu interface
+ *
+ ******************************************************************************/
+MTError CPhone::SetRemoteUUAddress( struct sockaddr_in sockaddr )
+{
+ iUdpAirInterface.SetRemoteAddress( sockaddr );
+ return MTL_SUCCESS;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD: Gets the remote address for the uu interface
+ *
+ ******************************************************************************/
+MTError CPhone::GetRemoteUUAddress( struct sockaddr_in *sockaddr )
+{
+ iUdpAirInterface.GetRemoteAddress( sockaddr );
+ return MTL_SUCCESS;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD: Gets the local address for the uu interface.
+ *
+ ******************************************************************************/
+MTError CPhone::GetLocalUUAddress( struct sockaddr_in *sockaddr )
+{
+ assert( sockaddr != NULL );
+ iUdpAirInterface.GetLocalAddress( sockaddr );
+ return MTL_SUCCESS;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: SERVER-THREAD: Sets the socket to be used by the TE channel.
+ *
+ ******************************************************************************/
+MTError CPhone::SetTeSocket( int aSock )
+{
+ TChannelError cerr;
+ cerr = iTcpTeChannel.SetSocket( aSock );
+ assert( (cerr == CE_NONE) || (cerr == CE_SOCKET_ALREADY_SET) );
+ return ((cerr == CE_NONE) ? MTL_SUCCESS : MTL_TE_CHANNEL_SOCKET_ALREADY_SET);
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD: Returns a pointer to the log.
+ *
+ ******************************************************************************/
+CLog *CPhone::GetLog()
+{
+ return &iLog;
+}
+
+
+/*******************************************************************************
+ *
+ * PUBLIC METHOD: RPC-THREAD: Gets the current status of the MT.
+ *
+ ******************************************************************************/
+MTStatus CPhone::GetStatus()
+{
+ TThreadError terr;
+
+ // if the status is MTS_SHUTDOWN_ALL_BUT_MAIN then we check to see if the
+ // main thread has exited and then we update it
+ if( iStatus == MTS_SHUTDOWN_ALL_BUT_MAIN ) {
+ terr = iMainThread.WaitForThread( 0 );
+ if( terr == TE_NONE ) {
+ iStatus = MTS_SHUTDOWN_ALL;
+ }
+ }
+
+ // return the status
+ return iStatus;
+}
+
+
+/*******************************************************************************
+ *
+ * Cleanupstate - cleans up everything
+ *
+ ******************************************************************************/
+void CPhone::CleanupState( int aRequestSource )
+{
+ int err;
+ TThreadState thread_state;
+ TThreadError terr;
+
+ // if the air interface thread is still listening then stop it
+ thread_state = iAirInterfaceThread.GetThreadState();
+ if( thread_state == TS_ACTIVE ) {
+ err = iUdpAirInterface.StopInterface();
+ assert( err == 0 );
+ terr = iAirInterfaceThread.WaitForThread( INFINITE );
+ assert( terr == TE_NONE );
+ }
+
+ // if the te channel thread is still listening then stop it
+ thread_state = iTEChannelThread.GetThreadState();
+ if( thread_state == TS_ACTIVE ) {
+ iTcpTeChannel.StopChannel();
+ terr = iTEChannelThread.WaitForThread( INFINITE );
+ assert( terr == TE_NONE );
+ }
+
+ // Remove the datalink layer
+ DeleteDatalinkLayer();
+
+ // Remove the fitler
+ DeleteFilters();
+
+ // update the status
+ thread_state = iMainThread.GetThreadState();
+ iStatus = ((thread_state == TS_ACTIVE) ? MTS_SHUTDOWN_ALL_BUT_MAIN : MTS_SHUTDOWN_ALL);
+
+ // verification
+ assert( (iStatus == MTS_SHUTDOWN_ALL) || (aRequestSource == CLEANUP_SOURCE_INTERNAL_RUN_PHONE) );
+}
+
+
+/*******************************************************************************
+ *
+ * SECTION: Helpers
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Create And Delete filters layers
+ *
+ ******************************************************************************/
+MTError CPhone::CreateFilters( int aFilterConfig )
+{
+ // if the config isn't zero or one then we have an error
+ if( (aFilterConfig != 0) && (aFilterConfig != 1) ) {
+ return MTL_INVALID_FILTER_CONFIG;
+ }
+
+ // the only filter is the ppp logger filter
+ if( aFilterConfig == FILTER_PPP ) {
+ iFilter = &iFilterPpp;
+ }
+
+ // done
+ return MTL_SUCCESS;
+}
+
+void CPhone::DeleteFilters()
+{
+ // just set the pointer to NULL
+ iFilter = NULL;
+}
+
+
+/*******************************************************************************
+ *
+ * CreateAndDelete Datalink layers - these are the methods who know the class
+ * (rather than the interface) of the datalink layer.
+ *
+ ******************************************************************************/
+MTError CPhone::CreateDatalinkLayer( int aDatalinkConfig )
+{
+ // create the appropriate datalink layer object and set the process data pointer
+ if( aDatalinkConfig == DL_NULL ) {
+ iDatalinkNull = new CDatalinkNull( &iPhoneData, &iLog );
+ assert( iDatalinkNull != NULL );
+ iProcessData = iDatalinkNull;
+ } else if( aDatalinkConfig == DL_PACKETISE ) {
+ iDatalinkPacketise = new CDatalinkPacketise( &iPhoneData, &iLog );
+ assert( iDatalinkPacketise != NULL );
+ iProcessData = iDatalinkPacketise;
+ } else {
+ return MTL_INVALID_DATALINK_LAYER;
+ }
+
+ // success
+ return MTL_SUCCESS;
+}
+
+void CPhone::DeleteDatalinkLayer()
+{
+ // delete whichever datalink layers are active
+ if( iDatalinkNull != NULL ) {
+ delete iDatalinkNull;
+ iDatalinkNull = NULL;
+ iProcessData = NULL;
+ }
+
+ if( iDatalinkPacketise != NULL ) {
+ delete iDatalinkPacketise;
+ iDatalinkPacketise = NULL;
+ iProcessData = NULL;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * SECTION: Thread entry procedures
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Thread Entry Procedures
+ *
+ ******************************************************************************/
+int MainThreadProc( CPhone *aPhone )
+{
+ MTError merr;
+ CLog *log;
+ int errcode;
+
+ // check the param
+ assert( aPhone != NULL );
+
+ // log
+ log = &(aPhone->iLog);
+ log->WriteLogEntry( SV_INFO, "MainThreadProc", "Started" );
+
+ // now call startup
+ merr = aPhone->InternalRunPhone( &errcode );
+
+ // the result is logged
+ if( merr != MTL_SUCCESS ) {
+ log->WriteLogEntry( SV_WARNING, "MainThreadProc", "InternalRunPhone returned error", merr, errcode );
+ }
+
+ // log
+ log->WriteLogEntry( SV_INFO, "MainThreadProc", "Stopped" );
+ return MTL_SUCCESS;
+}
+
+
+int AirInterfaceThreadProc( CPhone *aPhone )
+{
+ TAirInterfaceError aerr;
+ int errcode;
+ CUDPAirInterface *air_interface;
+ CLog *log;
+
+ // check the param
+ assert( aPhone != NULL );
+
+ // log
+ log = &(aPhone->iLog);
+ log->WriteLogEntry( SV_INFO, "AirInterfaceThreadProc", "Started" );
+
+ // now recv from the air interface
+ air_interface = &(aPhone->iUdpAirInterface);
+ aerr = air_interface->ListenOnInterface( &errcode );
+
+ // the result is logged
+ if( aerr != AIE_NONE ) {
+ log->WriteLogEntry( SV_WARNING, "AirInterfaceThreadProc", "ListenOnInterface returned error", aerr, errcode );
+ }
+
+ // log
+ log->WriteLogEntry( SV_INFO, "AirInterfaceThreadProc", "Stopped" );
+ return MTL_SUCCESS;
+}
+
+int TEChannelThreadProc( CPhone *aPhone )
+{
+ TChannelError cerr;
+ int errcode;
+ CTcpTeChannel *te_channel;
+ CLog *log;
+
+ // check the param
+ assert( aPhone != NULL );
+
+ // log
+ log = &(aPhone->iLog);
+ log->WriteLogEntry( SV_INFO, "TEChannelThreadProc", "Started" );
+
+ // now recv from the channel
+ te_channel = &(aPhone->iTcpTeChannel);
+ cerr = te_channel->ListenOnChannel( &errcode );
+
+ // the result is logged
+ if( cerr != CE_NONE ) {
+ log->WriteLogEntry( SV_WARNING, "TEChannelThreadProc", "ListenOnChannel returned error", cerr, errcode );
+ }
+
+ // log
+ log->WriteLogEntry( SV_INFO, "TEChannelThreadProc", "Stopped" );
+ return MTL_SUCCESS;
+}