/***************************************************************************
                   cc_statd Worker ( Worker.cpp )
                -----------------------------------------

	begin      : 2013/05/30
	copyright  : (C) 2013 Solbox Inc.
	author     : Development 1 Team
					- 2013/05/30 - 1st dadamin
	email      : dev1@solbox.com
	version    : 3.2.0

	CopyRight(C) 2005 Solbox Inc. All Rights reserved.
	Redistribution and use in source and binary forms, with or with out
	modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#include "cc_statd.h"
#include "Worker.h"
#include "Signals.h"
#include "Configs.h"
#include "Service.h"
#include "Logger.h"

static int _isExit = 0;
static pid_t _FailMonPid = -1;
static pid_t _MainPid = -1;
static CService * _WorkService = NULL;

static void SigTermWorker( int nSignalNumber )
{
	if(_isExit)	return;
	_isExit = 1;
	if(_WorkService)
		_WorkService->Stop();

	ostringstream msg;
	// Signal Number 에 따른 로깅처리.
	if( nSignalNumber == SIGTERM )
	{
		msg << "Worker Process [" << getpid() << "] exit job start by user signal [SIGTERM]";
	}
	else
	{
		msg << "Worker Process [" << getpid() << "] exit job start by user signal ["<< nSignalNumber <<"]";
	}

	cout << msg.str() << endl;
	_LOG(LWAR, msg.str().c_str());
}


/// @brief Worker Process 의 main 함수
static int WorkerMain( bool isDaemon, CService * s)
{
	// Set Signal Handler
	SetIgnoreSignal(isDaemon);
	SetSIGTERM(isDaemon, SigTermWorker);		

	_WorkService = s;
	// service start
	if(s->Create())
		s->Start();
	else
		_isExit = 2;

	// signal wait
	while ( _isExit == 0 )
	{
#ifdef _DEBUG
		cout << "Working ..." << endl;
#endif //_DEBUG
		pause();
	}

	// service stop
	s->Stop();

	if( _isExit > 1 )
	{
		// The main process exit process
		LOG( LERR, "Worker process create failed. Exit...");
		kill(_MainPid, SIGTERM);
	}

	_LOG( LWAR, "Worker Process[%d] exit.. Good Bye..", getpid());
	CLogger::Exit();
	CMyConfig::Exit();

	// 잠시 대기 후 종료처리.
	usleep(500000);

	return (_isExit == 1 ? EXIT_SUCCESS: EXIT_FAILURE);
}

/// TCP Process
static void MakeTCPProcess( bool isDaemon )
{
	pid_t processId;

	// Worker 프로세스 fork
	processId = fork();
	if( processId < 0 ) // Fork fail
	{
		int errorNum = errno;
		LOG( LERR, "TCP Process create failed. [%d][%s]", errorNum, strerror(errorNum) );
	}
	else if( processId == 0 ) // Child Process => Worker Process
	{
		// Worker Process Main 함수 호출 및 종료처리.
		int n = EXIT_FAILURE;
		CServiceFactory f;
		CService * p = f.CreateSerivce(SERVICE_TYPE::TCP_SERVICE);
		if(p)
		{
			n = WorkerMain( isDaemon, p );
			delete p;
		}

		exit( n );
	}
	else // Parent Process => Logging
	{
		LOG( LINF, "TCP Process create success. PID[%d]" , processId);
		// 잠시 대기
		usleep(100000);
	}
}

/// fail log monitor
static void MakeFailMon( bool isDaemon )
{
	pid_t processId;

	// Worker 프로세스 fork
	processId = fork();
	if( processId < 0 ) // Fork fail
	{
		int errorNum = errno;
		LOG( LERR, "FailMon Process create failed. [%d][%s]", errorNum, strerror(errorNum) );
	}
	else if( processId == 0 ) // Child Process => Worker Process
	{
		// Worker Process Main 함수 호출 및 종료처리.
		int n = EXIT_FAILURE;
		CServiceFactory f;
		CService * p = f.CreateSerivce(SERVICE_TYPE::FAIL_MON);
		if(p)
		{
			n = WorkerMain( isDaemon, p );
			delete p;
		}

		exit( n );
	}
	else // Parent Process => Logging
	{	
		_FailMonPid = processId;
		LOG( LINF, "FailMon Process create success. PID[%d]" , processId);
		// 잠시 대기
		usleep(100000);
	}
}

/// @brief Worker Process 재생성(fork) 처리 함수
/// @return 생성 성공시 true, 실패시에는 false 를 반환.
bool ReMakeProcessWorker( bool isDaemon, int killpid )
{
	if(killpid == _FailMonPid)
		MakeFailMon(isDaemon);
	else
		MakeTCPProcess(isDaemon);

	return true;
}

/// @brief Worker Process 생성 처리 함수
/// @return 생성 성공시 true, 실패시에는 false 를 반환.
bool MakeProcessWorker( bool isDaemon )
{
	_MainPid = getpid();
	// fail log monitor		
	MakeFailMon(isDaemon);	
	
	// TCP Process
	CTCPService::SetPort(CMyConfig::GetInstance()->GetTCPListenPort());
	if( CTCPService::MakeListenSocket() == false) 
		return false;

	// Conf 에 정의된 Worker Process Count 만큼 Worker 프로세스 생성 처리.
	for( int index = 0; index < CMyConfig::GetInstance()->GetWorkProcessCnt(); index++ )
	{
		MakeTCPProcess(isDaemon);
	}

	return true;
}
