This commit is contained in:
biosvos
2026-08-07 17:38:18 +09:00
commit 873193a243
9613 changed files with 2755992 additions and 0 deletions
+389
View File
@@ -0,0 +1,389 @@
#include "WorkerSendInfo.h"
#include "Logger.h"
#include "ProcessRename.h"
#include "ShmManager.h"
#include "ProcessConfig.h"
#include "AliveFhsCacheThread.h"
#include "SocketSendInfo.h"
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <time.h>
// 요청 수신 관련 최대 대기 시간. (sec)
#define MAX_REQUEST_TIMEOUT 60
// 공유메모리에 Data Set, Get 을 담당할 객체에 대한 포인터.
// Main.cpp 에 전역변수로 정의 되어 있다.
extern CShmManager * g_pShmManager;
// FHS 의 vmasd 가 Broadcasting 하는 각 FHS 의 상태 정보를 수신받기 위한 UDP Socket....
// Main.cpp 에 전역변수로 정의 되어 있다.
extern int g_sockVmasdRecv;
// FHS csagentd 가 전송하는 시스템 상태 정보 수신을 위한 TCP Socket
// Main.cpp 에 전역변수로 정의 되어 있다.
extern int g_sockSystemRecv;
// FHS csagentd 가 전송하는 서비스 상태 체크 정보 수신을 위한 TCP Socket
// Main.cpp 에 전역변수로 정의 되어 있다.
extern int g_sockCheckRecv;
// fimngd 등과 같은 외부 모듈과 통신을 통해 정보를 전달하기 위한 TCP Socket 생성.
// Main.cpp 에 전역변수로 정의 되어 있다.
extern int g_sockInfoSend;
// Alive FHS Cache Thread 객체 대한 포인터.
CAliveFhsCacheThread * g_pThreadAliveFhs = NULL;
// 각 Client 를 처리할 Thread 에 전달할 구조체
struct stSendInfoThreadArg {
// client socket descriptor
int clientSocketDesc;
// Client 의 IP 주소 정보를 저장한 변수
// - 공유메모리 client_ip 항목 크기와 동일한 크기로 설정.
char szClientAddress[IP_ADDR_LENGTH];
};
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
void ReadyToExitWorkerSendInfo()
{
// open 된 socket 관련 Close 처리
if( g_sockInfoSend != -1 )
close( g_sockInfoSend );
// Logger 객체 종료 처리.
CLogger::Exit();
return;
}
// Worker SendInfo 프로세스에 대한 대한 종료 처리 수신시.
static void SignalWorkerSendInfoTerminate( int nSignalNumber )
{
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
_LOG( LINF, "[SendInfo:%d] Process exit by SIGTERM signal. Good Bye..", getpid() );
}
else
{
_LOG( LWAR, "[SendInfo:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
}
ReadyToExitWorkerSendInfo();
// 종료전 잠시 대기
struct timespec sleep;
sleep.tv_sec = 0;
sleep.tv_nsec = 500000000; // 0.5 sec
nanosleep( &sleep, NULL );
exit( EXIT_SUCCESS );
}
// Worker::SendInfo Process 의 signal 처리기...
void SetWorkerSendInfoSignalHandler()
{
sigset_t set;
struct sigaction act;
memset( &act, 0x00, sizeof( act ) );
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
sigfillset( &act.sa_mask );
// 무시 처리 signal
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */
// Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함.
act.sa_handler = SIG_IGN;
sigaction( SIGCHLD, &act, NULL );
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SignalWorkerSendInfoTerminate;
sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */
// 나머지 신호는 default 처리.
sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask( SIG_SETMASK, &set, NULL );
}
// Worker::SendInfo 에서 각 Client 에 대한 처리를 수행하기 위한 Thread.
void * WorkerSendInfoClientThread( void * arg )
{
// 전달받은 변수를 내부 변수에 저장 처리.
// client socket 관련 처리 변수 생성
CSocketSendInfo clientSocket( ( ( struct stSendInfoThreadArg * ) arg )->clientSocketDesc );
// client 주소 처리 관련
char szClientAddress[IP_ADDR_LENGTH];
memcpy( szClientAddress, ( ( struct stSendInfoThreadArg * ) arg )->szClientAddress, IP_ADDR_LENGTH );
// malloc 로 생성된 변수 해제 처리
free( arg );
// 본 thead 는 client 연결 상태에 따라 종료되므로.. process 에서 분리 처리
pthread_detach( pthread_self() );
_LOG( LINF, "[SendInfo:%d] client thread start. [%s]", getpid(), szClientAddress );
// 송수신 처리 관련 변수
int nResult;
char command;
// hostname 수신 정보를 저장하기 위한 변수.
std::string strHostname;
// Alive FHS 목록정보 저장 처리를 위한 vector
std::vector<struct FhsServiceStatInfo> vecAliveFhs;
// socket 수신 대기
while( 1 )
{
// 요청 수신 대기
nResult = clientSocket.GetPacketHeader( command, MAX_REQUEST_TIMEOUT );
if( nResult == 0 )
{
// timeout 발생시...
// - server 모드로 동작하므로... 지정된 시간동안 요청이 없는 경우 세션을 종료 처리한다.
_LOG( LINF, "[SendInfo:%d] client[%s] request timeout[%d]. session close.", getpid(), szClientAddress, MAX_REQUEST_TIMEOUT );
break;
}
else if( nResult < 0 )
{
// Socket 종료, 오류 또는 정의되지 않은 형식의 패킷 header 수신시...
// 오류 내역은 socket 모듈에서 로깅하므로... 그냥 종료 처리.
break;
}
else
{
// 정상 header 수신시.
// - 수신된 command 에 따른 처리.
if( command == COMMAND_ALIVE_FHS )
{
// Alive FHS 목록 요청인 경우..
// Body 부분에 대한 처리.
// - 각 protocol version 별 처리.
if( clientSocket.GetPacketBodyAliveFhs( strHostname ) == false )
{
// Data 수신 실패, 지원하지 않는 protocol version 또는 RC ID 정보가 다른 경우....
// - 세션 종료 처리.
// - 오류 내역은 위의 해당 함수에서 client 로 전송 처리함.
LOG( LERR, "[SendInfo:%d] client[%s] alive fhs request body fail. session close.", getpid(), szClientAddress );
break;
}
// Alive FHS 목록 조회.
vecAliveFhs.clear();
if( g_pThreadAliveFhs->GetAliveFhs( vecAliveFhs ) == -1 )
{
// 공유메모리의 FHS 정보가 아직 불완전하여 SKIP 처리해야 하는 경우.
if( clientSocket.SendResultAliveFhsSkip() == false )
{
// 전송 실패 발생시.
LOG( LERR, "[SendInfo:%d] client[%s][%s] alive fhs skip send error. session close."
, getpid(), szClientAddress, strHostname.c_str() );
break;
}
}
else
{
// Alive FHS 목록 전송 처리.
if( clientSocket.SendResultAliveFhs( vecAliveFhs ) == false )
{
// 전송 실패 발생시.
LOG( LERR, "[SendInfo:%d] client[%s][%s] alive fhs send error. session close."
, getpid(), szClientAddress, strHostname.c_str() );
break;
}
else
{
// 전송 성공시
_LOG( LDBG, "[SendInfo:%d] client[%s][%s] alive fhs send ok. fhs count[%zu]"
, getpid(), szClientAddress, strHostname.c_str(), vecAliveFhs.size() );
}
}
}
else
{
// 정의되지 않은 command 인 경우..
// - 오류 로깅 후 세션 종료 처리.
LOG( LERR, "[SendInfo:%d] client[%s] request type not defined. session close.", getpid(), szClientAddress );
clientSocket.PrintHeaderToLog();
break;
}
}
}
// client 와 연결 종료 처리.
clientSocket.Close();
_LOG( LINF, "[SendInfo:%d] client connection closed. [%s]", getpid(), szClientAddress );
// Thread 종료 관련 처리.
return NULL;
}
// Worker::SendInfo 프로세스의 Main 역활을 수행하기 위한 함수.
int WorkerSendInfoMain()
{
// 전역 변수로 설정된 socket 중 해당 worker 에서 사용하지 않는 socket 은 close 처리한다.
if( g_sockVmasdRecv != -1 )
{
close( g_sockVmasdRecv );
g_sockVmasdRecv = -1;
}
if( g_sockSystemRecv != -1 )
{
close( g_sockSystemRecv );
g_sockSystemRecv = -1;
}
if( g_sockCheckRecv != -1 )
{
close( g_sockCheckRecv );
g_sockCheckRecv = -1;
}
// Process Rename..
set_ps_display( PROG_NAME": SendInfo", false );
// Set Signal Handler
SetWorkerSendInfoSignalHandler();
// 사용할 객체 초기화 처리
// Alive FHS 목록을 주기적으로 추출할 Thread 모듈 초기화 및 기동 처리.
CAliveFhsCacheThread threadAliveFhsCache( g_pShmManager );
if( threadAliveFhsCache.Start() == false )
{
_LOG( LWAR, "[SendInfo:%d] alive fhs cache thread create failed. => Process Exit", getpid() );
ReadyToExitWorkerSendInfo();
return EXIT_FAILURE; // EXIT_FAILURE 를 반환하여 재생성 처리 방지...
}
// 각 Client thread 에서 해당 객체 접근이 가능토록 전역 포인터에 저장 처리.
g_pThreadAliveFhs = &threadAliveFhsCache;
// 접속 Client 에 대한 처리.
int clientSock;
struct sockaddr_in clientSockAddr;
socklen_t clientSockLen = sizeof( clientSockAddr );
pthread_t clientThreadId;
struct stSendInfoThreadArg * pThreadArg = NULL;
while( 1 )
{
clientSock = accept( g_sockInfoSend, ( struct sockaddr * ) &clientSockAddr, &clientSockLen );
if( clientSock == -1 )
{
// 오류 발생시.... 해당 내역 로깅 처리.
int errorNum = errno;
LOG( LERR, "[SendInfo:%d] client accept failed [%d][%s]", getpid(), errorNum, strerror( errorNum ) );
}
else
{
// 정상적인 Client 인 경우...
// 처리 Thread 로 전달할 변수를 malloc 로 생성 처리
pThreadArg = ( struct stSendInfoThreadArg * ) malloc( sizeof( struct stSendInfoThreadArg ) );
if( pThreadArg == NULL )
{
int errorNum = errno;
close( clientSock ); // client 접속 종료 처리.
char tempBuffer[IP_ADDR_LENGTH];
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
if( inet_ntop( AF_INET, &( clientSockAddr.sin_addr ), tempBuffer, sizeof( tempBuffer ) ) != NULL )
{
LOG( LERR, "[SendInfo:%d] client[%s] thread malloc failed [%d][%s]", getpid(), tempBuffer, errorNum, strerror( errorNum ) );
}
else
{
LOG( LERR, "[SendInfo:%d] client thread malloc failed [%d][%s] and inet_ntop error[%d][%s]"
, getpid(), errorNum, strerror( errorNum ), errno, strerror( errno ) );
}
continue;
}
else
{
// 인자로 전달할 변수정보 설정.
pThreadArg->clientSocketDesc = clientSock;
char tempBuffer[IP_ADDR_LENGTH];
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
if( inet_ntop( AF_INET, &( clientSockAddr.sin_addr ), tempBuffer, sizeof( tempBuffer ) ) != NULL )
{
memcpy( pThreadArg->szClientAddress, tempBuffer, sizeof( tempBuffer ) );
}
else
{
// inet_ntop 오류 발생시
// - IP 정보는 그냥 로깅 목적등으로 전달되는 정보이므로.. 0.0.0.0 으로 설정 처리한다.
int errorNum = errno;
LOG( LERR, "[SendInfo:%d] client ip not valid. inet_ntop error[%d][%s]", getpid(), errorNum, strerror( errorNum ) );
snprintf( pThreadArg->szClientAddress, IP_ADDR_LENGTH - 1, "0.0.0.0" );
}
// Client 처리를 담당할 Thread 생성 처리
if( pthread_create( &clientThreadId, NULL, WorkerSendInfoClientThread, (void *)pThreadArg ) != 0 )
{
// 생성 실패시...
// - 로깅
// - client socket close
// - malloc 로 생성된 전달 변수 free 처리.
int errorNum = errno;
LOG( LERR, "[SendInfo:%d] client[%s] thread create failed [%d][%s]"
, getpid(), pThreadArg->szClientAddress, errorNum, strerror( errorNum ) );
close( clientSock );
free( pThreadArg );
}
else
{
_LOG( LDBG, "[SendInfo:%d] client[%s] accept & client thread create ok.", getpid(), pThreadArg->szClientAddress );
}
}
}
} // while(1)
// 종료시 정리 작업 수행
ReadyToExitWorkerSendInfo();
return EXIT_SUCCESS;
}