/*
* 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:
* This file was autogenerated by rpcgen, but should be modified by the developer.
* Make sure you don't use the -component_mod flag in future or this file will be overwritten.
* Fri Oct 17 09:37:12 2003
*
*/
/****************************************************************************************
*
* System Includes
*
***************************************************************************************/
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
/****************************************************************************************
*
* Local Includes
*
***************************************************************************************/
#include "CSvcPppcontroller.h"
#include "CSPppcontroller.h"
#include "../include/standard_unix.h"
#include "../include/strncpynt.h"
#include "../DynamicsConfigurationLibrary/file_utilities.h"
/****************************************************************************************
*
* Definitions
*
***************************************************************************************/
#define MAXLOGNAME 64
#define MAXCOMMANDLINE 2048
#define MAXLOGLINELENGTH 1024
#define PPPD_BINARY "./pppd"
#define GATEWAY_BINARY "./pppdgateway"
#define MAXINTERFACENAMESIZE 64
#define MAXLISTLINES 32
#define CONNECTED_STRING "Script /etc/ppp/ip-up finished"
#define DISCONNECTED_STRING "Connection terminated"
#define IS_INLINE_WHITESPACE(c) (((c) == ' ')||((c) == '\t'))
/****************************************************************************************
*
* Implementation
*
***************************************************************************************/
CSPppcontroller::CSPppcontroller()
{
iProcess = NULL;
iSessionStatus = SS_NOT_STARTED;
}
CSPppcontroller::~CSPppcontroller()
{
assert( iProcess == NULL );
}
int CSPppcontroller::GetKey()
{
return iKey;
}
void CSPppcontroller::SetKey( int aKey )
{
iKey = aKey;
}
/****************************************************************************************
*
* PUBLIC FUNCTION: cstr_startpppsession
*
***************************************************************************************/
TResult CSPppcontroller::cstr_startpppsession( TPppSessionConfig aArgs )
{
int err, errcode;
TResult rv = { ERR_NONE, 0, 0 };
char logfilename[MAXLOGNAME];
char commandline[MAXCOMMANDLINE];
TCAProcessError perr;
// check that we are not already started
assert( iProcess == NULL );
// save the config
iSessionConfig = aArgs;
// construct the name of the logfile
snprintf( logfilename, MAXLOGNAME, "pppd%04d.log", iKey );
// remove the file if it exists -- if an error other than file not exists happens then exit
err = unlink( logfilename );
if( (err != 0) && (errno != ENOENT) ) {
rv.iStandardResult = ERR_LOG_FILE_ERROR;
rv.iExtendedCode = 0;
rv.iSystemError = errno;
return rv;
}
// construct the command line for the PPP session
#ifndef __UNIT_TEST_13
snprintf( commandline, MAXCOMMANDLINE, "%s pty \'%s %s %s %d\' logfile %s %s", PPPD_BINARY, GATEWAY_BINARY,
iSessionConfig.iMobsterAddress, iSessionConfig.iMobsterPort, iSessionConfig.iMTID, logfilename, iSessionConfig.iSessionConfiguration );
#else
snprintf( commandline, MAXCOMMANDLINE, "%s notty logfile %s %s", PPPD_BINARY, logfilename, iSessionConfig.iSessionConfiguration );
#endif
// now start the process
iProcess = new CAProcess();
assert( iProcess != NULL );
perr = iProcess->StartProcess( commandline, &errcode, false, false, true );
if( perr != CAE_NONE ) {
rv.iStandardResult = ERR_START_PROCESS_ERROR;
rv.iExtendedCode = (int)perr;
rv.iSystemError = errcode;
delete iProcess;
iProcess = NULL;
return rv;
}
// done - success
return rv;
}
/****************************************************************************************
*
* PUBLIC FUNCTION: dstr_removepppsession
*
***************************************************************************************/
TResult CSPppcontroller::dstr_removepppsession( int aArgs, int *aDeleteInstance )
{
TResult rv = { ERR_NONE, 0, 0 };
TCAProcessError perr;
TProcessStatus pstatus;
char logfilename[MAXLOGNAME];
// make sure that we still have a process
assert( iProcess != NULL );
// get the status of the process to make sure we are ok
perr = iProcess->GetProcessStatus( &pstatus );
assert( perr == CAE_NONE );
if( pstatus == PS_STARTED ) {
*aDeleteInstance = 0;
rv.iStandardResult = ERR_INVALIDSTATE;
return rv;
}
// remove the log file
snprintf( logfilename, MAXLOGNAME, "pppd%04d.log", iKey );
unlink( logfilename );
// ok - remove the process
delete iProcess;
iProcess = NULL;
// done - success
*aDeleteInstance = 1;
return rv;
}
/****************************************************************************************
*
* PUBLIC FUNCTION: killsession
*
***************************************************************************************/
TResult CSPppcontroller::killsession( int aArgs )
{
return StopProcessWithSignal( SIGKILL );
}
/****************************************************************************************
*
* PUBLIC FUNCTION: stopsession
*
***************************************************************************************/
TResult CSPppcontroller::stopsession( int aArgs )
{
return StopProcessWithSignal( SIGTERM );
}
/****************************************************************************************
*
* PUBLIC FUNCTION: getsessioninfo
*
***************************************************************************************/
TPppSessionDesc CSPppcontroller::getsessioninfo( int aArgs )
{
TPppSessionDesc rv;
TResult res;
int exitcode = 0;
TCAProcessError perr;
TProcessStatus pstatus = PS_INVALID;
TProcessExitReason preason = ER_INVALID;
// check state
assert( iProcess != NULL );
memset( &rv, 0, sizeof(rv) );
// interrogate the process
perr = iProcess->GetProcessStatus( &pstatus );
assert( perr == CAE_NONE );
if( (pstatus == PS_STOPPED) || (pstatus == PS_ABANDONNED) ) {
perr = iProcess->GetExitReason( &preason );
assert( perr == CAE_NONE );
}
if( (pstatus == PS_STOPPED) || (pstatus == PS_ABANDONNED) ) {
perr = iProcess->GetExitCode( &exitcode );
assert( perr == CAE_NONE );
}
// update the dynamic config
res = GetInterfaceName();
if( res.iStandardResult != ERR_NONE ) {
rv.iErrorCode = res.iStandardResult;
rv.iErrorDetail = res.iExtendedCode;
return rv;
}
res = UpdateSessionStatus();
if( res.iStandardResult != ERR_NONE ) {
rv.iErrorCode = res.iStandardResult;
rv.iErrorDetail = res.iExtendedCode;
return rv;
}
res = GetIPAddresses();
if( res.iStandardResult != ERR_NONE ) {
rv.iErrorCode = res.iStandardResult;
rv.iErrorDetail = res.iExtendedCode;
return rv;
}
// now return the info
rv.iErrorCode = ERR_NONE;
rv.iErrorDetail = 0;
rv.iConfig = iSessionConfig;
rv.iProcessStatus = (int)pstatus;
rv.iProcessExitReason = (int)preason;
rv.iProcessExitCode = exitcode;
rv.iSessionStatus = iSessionStatus;
STRNCPY_NULL_TERMINATE( rv.iInterfaceName, iInterfaceName.c_str(), MAXSESSIONNAMELEN );
rv.iLocalIPAddress = iLocalIPAddress;
rv.iRemoteIPAddress = iRemoteIPAddress;
return rv;
}
/****************************************************************************************
*
* PUBLIC FUNCTION: getppplog
*
***************************************************************************************/
TVarData CSPppcontroller::getppplog( int aArgs )
{
TVarData rv;
TResult res;
char logname[MAXLOGNAME];
// get the logfilename
snprintf( logname, MAXLOGNAME, "pppd%04d.log", iKey );
// now copy the file into the vardata buffer
res = CopyFileIntoBuffer( logname, &rv );
if( res.iStandardResult != ERR_NONE ) {
assert( rv.TVarData_len == 0 );
assert( rv.TVarData_val == NULL );
}
// done
return rv;
}
/****************************************************************************************
*
* PRIVATE FUNCTION: StopProcessWithSignal
*
***************************************************************************************/
TResult CSPppcontroller::StopProcessWithSignal( int aSignal )
{
TResult rv = { ERR_NONE, 0, 0 };
TCAProcessError perr;
TProcessStatus pstatus;
// since we create in the constructor and stop in the destructor there must be a process
assert( iProcess != NULL );
// if the process isn't running then it has died outside the scope of this controller,
// clean up the state, return an error since this is noteworthy and should be either
// expected or not happen.
perr = iProcess->GetProcessStatus( &pstatus );
assert( perr == CAE_NONE );
if( pstatus != PS_STARTED ) {
assert( (pstatus == PS_STOPPED) || (pstatus == PS_ABANDONNED) );
rv.iStandardResult = ERR_PROCESS_TERMINATED_OUTSIDE_SCOPE;
return rv;
}
// request the process to stop
perr = iProcess->RequestStop( aSignal );
if( perr != CAE_NONE ) {
rv.iStandardResult = ERR_STOP_PROCESS_ERROR;
rv.iExtendedCode = (int)perr;
return rv;
}
// wait for the process to stop
perr = iProcess->WaitForProcessToTerminate( -1 );
if( perr != CAE_NONE ) {
rv.iStandardResult = ERR_WAIT_PROCESS_ERROR;
rv.iExtendedCode = (int)perr;
return rv;
}
// done - success
return rv;
}
/****************************************************************************************
*
* PRIVATE FUNCTION: GetInterfaceName
*
***************************************************************************************/
TResult CSPppcontroller::GetInterfaceName()
{
TResult rv;
string line;
char interface_name[MAXINTERFACENAMESIZE];
// clear the interface (so if not found we don't have an old value)
iInterfaceName = "";
// we want to know the interface name, on line "Using interface pppX";
rv = GetTokenFromFile( "Using", &line, MM_FIRST );
if( rv.iStandardResult != ERR_NONE ) {
if( rv.iStandardResult == ERR_INVALIDARG ) {
rv.iStandardResult = ERR_NONE;
rv.iExtendedCode = 0;
}
return rv;
}
// now grab the interface name
sscanf( line.c_str(), "Using interface %s", interface_name );
iInterfaceName = interface_name;
// done - success;
return rv;
}
/****************************************************************************************
*
* PRIVATE FUNCTION: GetIPAddresses
*
***************************************************************************************/
TResult CSPppcontroller::GetIPAddresses()
{
TResult rv;
string line;
char address[MAXINTERFACENAMESIZE];
// clear old values
iLocalIPAddress = iRemoteIPAddress = 0;
// we want to know the local IP address
rv = GetTokenFromFile( "local IP address", &line, MM_LAST );
if( rv.iStandardResult != ERR_NONE ) {
if( rv.iStandardResult == ERR_INVALIDARG ) {
rv.iStandardResult = ERR_NONE;
rv.iExtendedCode = 0;
}
return rv;
}
// grab address
sscanf( line.c_str(), "local IP address %s", address );
iLocalIPAddress = inet_addr( address );
// we want to know the remote IP address
rv = GetTokenFromFile( "remote IP address", &line, MM_LAST );
if( rv.iStandardResult != ERR_NONE ) {
if( rv.iStandardResult == ERR_INVALIDARG ) {
rv.iStandardResult = ERR_NONE;
rv.iExtendedCode = 0;
}
return rv;
}
// grab address
sscanf( line.c_str(), "remote IP address %s", address );
iRemoteIPAddress = inet_addr( address );
// done - success;
return rv;
}
/****************************************************************************************
*
* PRIVATE FUNCTION: UpdateSessionStatus
*
***************************************************************************************/
TResult CSPppcontroller::UpdateSessionStatus()
{
TResult rv = { ERR_NONE, 0, 0 };
TFUError ferr;
int mline[MAXLISTLINES], match_count, errcode, once_connected, disconnected;
char logfilename[MAXLOGNAME];
struct stat fstat;
// get the logfilename
snprintf( logfilename, MAXLOGNAME, "pppd%04d.log", iKey );
// see if the file exists - if not then the status is SS_NOT_STARTED
errcode = stat( logfilename, &fstat );
if( (errcode == -1) && (errno == ENOENT) ) {
iSessionStatus = SS_NOT_STARTED;
return rv;
}
// look for the line with the CONNECTED_STRING prefix
match_count = MAXLISTLINES;
ferr = FindMatchingLinesByRawPrefix( logfilename, CONNECTED_STRING, mline, &match_count, &errcode );
if( ferr != FUE_NONE ) {
rv.iStandardResult = ERR_LOG_FILE_ERROR;
rv.iExtendedCode = (int)ferr;
rv.iSystemError = errcode;
return rv;
}
once_connected = ((match_count > 0) ? 1 : 0);
// look for the line with the DISCONNECTED_STRING prefix
match_count = MAXLISTLINES;
ferr = FindMatchingLinesByRawPrefix( logfilename, DISCONNECTED_STRING, mline, &match_count, &errcode );
if( ferr != FUE_NONE ) {
rv.iStandardResult = ERR_LOG_FILE_ERROR;
rv.iExtendedCode = (int)ferr;
rv.iSystemError = errcode;
return rv;
}
disconnected = ((match_count > 0) ? 1 : 0);
// set the state based on the log
if( (once_connected == 0) && (disconnected == 0) ) {
iSessionStatus = SS_CONNECTING;
} else if( (once_connected == 1) && (disconnected == 0) ) {
iSessionStatus = SS_CONNECTED;
} else if( (once_connected == 1) && (disconnected == 1) ) {
iSessionStatus = SS_DISCONNECTED;
} else if( (once_connected == 0) && (disconnected == 1) ) {
iSessionStatus = SS_DISCONNECTED;
}
// done - success
return rv;
}
/*******************************************************************************
*
* PRIVATE FUNCTION: CopyFileIntoBuffer
*
******************************************************************************/
TResult CSPppcontroller::CopyFileIntoBuffer( char *aFilename, TVarData *aData )
{
TResult rv = { ERR_NONE, 0, 0 };
int err;
int filesize;
int i;
char c;
FILE *fp;
// check params
assert( aFilename != NULL );
assert( aData != NULL );
// initialise the data to empty
aData->TVarData_val = NULL;
aData->TVarData_len = 0;
// open the logfile
fp = fopen( aFilename, "rb" );
if( fp == NULL ) {
rv.iStandardResult = ERR_LOG_FILE_ERROR;
rv.iExtendedCode = 0;
rv.iSystemError = errno;
return rv;
}
// get the file size
fseek( fp, 0, SEEK_END );
filesize = ftell( fp );
fseek( fp, 0, SEEK_SET );
// if the filesize is zero then just return
if( filesize == 0 ) {
return rv;
}
// allocate space for the file data
aData->TVarData_val = (char*)calloc( (filesize + 1), 1 );
assert( aData->TVarData_val != NULL );
aData->TVarData_len = (filesize + 1);
// now copy the data
for( i = 0; i < filesize; i++ ) {
// read one byte
err = fread( &c, 1, 1, fp );
if( err != 1 ) {
free( aData->TVarData_val );
aData->TVarData_val = NULL;
aData->TVarData_len = 0;
rv.iStandardResult = ERR_LOG_FILE_ERROR;
rv.iExtendedCode = 0;
rv.iSystemError = errno;
fclose( fp );
return rv;
}
// save the byte in the buffer
(aData->TVarData_val)[i] = c;
}
// cleanup and return
fclose( fp );
return rv;
}
/****************************************************************************************
*
* PRIVATE FUNCTION: GetTokenFromFile
*
***************************************************************************************/
TResult CSPppcontroller::GetTokenFromFile( string aPrefix, string *aLine, TMultiMatchSemantics aMultiMatchSemantics )
{
TResult rv = { ERR_NONE, 0, 0 };
TFUError ferr;
char logfilename[MAXLOGNAME];
char cline[MAXLOGLINELENGTH];
int mline[MAXLISTLINES], match_count, errcode, entry;
struct stat fstat;
// check params
assert( aLine != NULL );
// get the logfilename
snprintf( logfilename, MAXLOGNAME, "pppd%04d.log", iKey );
// fprintf( stderr, "DEBUG: request for lines starting with '%s'\n", aPrefix.c_str() );
// see if the file exists - if not then just return - this is NOT an error
errcode = stat( logfilename, &fstat );
if( (errcode == -1) && (errno == ENOENT) ) {
rv.iStandardResult = ERR_INVALIDARG;
rv.iExtendedCode = 1;
// fprintf( stderr, "DEBUG: file doesn't exist.\n" );
return rv;
}
// look for the lines that match the prefix
match_count = MAXLISTLINES;
ferr = FindMatchingLinesByRawPrefix( logfilename, (char*)aPrefix.c_str(), mline, &match_count, &errcode );
if( ferr != FUE_NONE ) {
rv.iStandardResult = ERR_LOG_FILE_ERROR;
rv.iExtendedCode = (int)ferr;
rv.iSystemError = errcode;
// fprintf( stderr, "DEBUG: error parsing logfile.\n" );
return rv;
}
// if there is no match then nothing to do
if( match_count == 0 ) {
rv.iStandardResult = ERR_INVALIDARG;
rv.iExtendedCode = 2;
// fprintf( stderr, "DEBUG: no matches.\n" );
return rv;
}
// if there are multiple matches then print warning (just for the admin)
if( match_count > 1 ) {
// fprintf( stderr, "WARNING: multiple matches for token \"%s\" in '%s'.\n", aPrefix.c_str(), logfilename );
}
// handle multiple matches
if( (aMultiMatchSemantics == MM_ERROR) && (match_count > 1) ) {
rv.iStandardResult = ERR_MULTIPLE_MATCHES_IN_LOG_FILE;
return rv;
}
entry = ((aMultiMatchSemantics == MM_FIRST) ? 0 : (match_count-1));
// now get the matching line
ferr = GetLine( logfilename, mline[entry], cline, MAXLOGLINELENGTH, &errcode );
if( ferr != FUE_NONE ) {
rv.iStandardResult = ERR_LOG_FILE_ERROR;
rv.iExtendedCode = (int)ferr;
rv.iSystemError = errcode;
// fprintf( stderr, "DEBUG: error getting the matching line.\n" );
return rv;
}
// copy the line into the passed buffer
(*aLine) = cline;
// fprintf( stderr, "DEBUG: successfully retrieved line '%s'\n", aLine->c_str() );
// done - success;
return rv;
}