故障導向安全的架構實例-EasyDarwin的實現

故障導向安全的架構實例-EasyDarwin的實現

如題,如果系統出現了Error級別的LOG,那麼會導致服務進程重啟,下面主要講述下機制:

void Utility::MyLogErr(char *msg){ //qtss_printf(msg); QTSServerInterface::LogError(qtssFatalVerbosity, msg);}void QTSServerInterface::LogError(QTSS_ErrorVerbosity inVerbosity, char* inBuffer) { QTSS_RoleParams theParams; theParams.errorParams.inVerbosity = inVerbosity; theParams.errorParams.inBuffer = inBuffer; for (UInt32 x = 0; x < QTSServerInterface::GetNumModulesInRole(QTSSModule::kErrorLogRole); x++) (void)QTSServerInterface::GetModule(QTSSModule::kErrorLogRole, x)->!CallDispatch(QTSS_ErrorLog_Role, &theParam); // If this is a fatal error, set the proper attribute in the RTSPServer dictionary if ((inVerbosity == qtssFatalVerbosity) && (sServer != NULL)) { QTSS_ServerState theState = qtssFatalErrorState; (void)sServer->SetValue(qtssSvrState, 0, &theState, sizeof(theState)); }}

我們看看qtssSvrState這個參數的解釋:

qtssSvrState = 8, r/w QTSS_ServerState The current state of the server. If a module sets the server state, the server will respond in the appropriate fashion. Setting to qtssRefusingConnectionsState causes the server to refuse connections, setting to qtssFatalErrorState or qtssShuttingDownState causes the server to quit.

這個參數是服務器狀態參數,如果有某個模塊設置了這個狀態,服務器會以合適的方式回應,如果設置成了qtssRefusingConnectionsState狀態,則服務器會拒絕連接;如果設置成了qtssFatalErrorState或者qtssShuttingDownState狀態,則會導致服務器重啟。

在main函數,也就是

int main(int argc, char * argv[]) { ... //This function starts, runs, and shuts down the server if (::StartServer(&theXMLParser, &theMessagesSource, thePort, statsUpdateInterval, theInitialState, dontFork, debugLevel, debugOptions) != qtssFatalErrorState) { ::RunServer(); CleanPid(false); exit (EXIT_SUCCESS); } else exit(-1); //Cant start server don't try again}
void RunServer(){  Bool16 restartServer = false; UInt32 loopCount = 0; UInt32 debugLevel = 0; Bool16 printHeader = false; Bool16 printStatus = false; //just wait until someone stops the server or a fatal error occurs. QTSS_ServerState theServerState = sServer->GetServerState(); while ((theServerState != qtssShuttingDownState) && (theServerState != qtssFatalErrorState)) {#ifdef __sgi__ OSThread::Sleep(999);#else OSThread::Sleep(1000);#endif LogStatus(theServerState); if (sStatusUpdateInterval) { debugLevel = sServer->GetDebugLevel();  printHeader = PrintHeader(loopCount); printStatus = PrintLine(loopCount);  if (printStatus) { if (DebugOn(sServer) ) // debug level display or logging is on DebugStatus(debugLevel, printHeader);  if (!DebugDisplayOn(sServer)) PrintStatus(printHeader); // default status output }   loopCount++; }  if ((sServer->SigIntSet()) || (sServer->SigTermSet())) { // // start the shutdown process theServerState = qtssShuttingDownState; (void)QTSS_SetValue(QTSServerInterface::GetServer(), qtssSvrState, 0, &theServerState, sizeof(theServerState)); if (sServer->SigIntSet()) restartServer = true; }  theServerState = sServer->GetServerState(); if (theServerState == qtssIdleState) sServer->KillAllRTPSessions(); }  // // Kill all the sessions and wait for them to die, // but don't wait more than 5 seconds sServer->KillAllRTPSessions(); for (UInt32 shutdownWaitCount = 0; (sServer->GetNumRTPSessions() > 0) && (shutdownWaitCount < 5); shutdownWaitCount++) OSThread::Sleep(1000);  //Now, make sure that the server can't do any work TaskThreadPool::RemoveThreads();  //now that the server is definitely stopped, it is safe to initate //the shutdown process delete sServer;  CleanPid(false); //ok, we're ready to exit. If we're quitting because of some fatal error //while running the server, make sure to let the parent process know by //exiting with a nonzero status. Otherwise, exit with a 0 status if (theServerState == qtssFatalErrorState || restartServer) ::exit (-2);//-2 signals parent process to restart server}

在RunServer函數里,如果server的狀態是qtssFatalErrorState,則會調用exit(-2),該進程會退出,那麼在該進程又是如何重啟的呢?其實,在流媒體服務器啟動後會在系統中創建兩個進程,子進程服務流媒體服務,父進程負責對子進程進行管理,例如檢查子進程是否退出,如果退出,則依據配置文件的配置而覺得是否重啟子進程。

在main函數中,截獲了系統信號SIGINT信號,如果截獲到了這些信號(如下代碼所示)則會調用到sigcatcher函數,該函數里會判斷如果是SIGINT信號,則會kill子進程。

int main(int argc, char * argv[]) { extern char* optarg;   // on write, don't send signal for SIGPIPE, just set errno to EPIPE // and return -1 //signal is a deprecated and potentially dangerous function //(void) ::signal(SIGPIPE, SIG_IGN); struct sigaction act; #if defined(sun) || defined(i386) || defined(__x86_64__) || defined (__MacOSX__) || defined(__powerpc__) || defined (__osf__) || defined (__sgi_cc__) || defined (__hpux__) || defined (__linux__) sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = (void(*)(int))&sigcatcher;#elif defined(__sgi__)  sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = (void(*)(...))&sigcatcher;#else act.sa_mask = 0; act.sa_flags = 0; act.sa_handler = (void(*)(...))&sigcatcher;#endif (void)::sigaction(SIGPIPE, &act, NULL); (void)::sigaction(SIGHUP, &act, NULL); (void)::sigaction(SIGINT, &act, NULL); (void)::sigaction(SIGTERM, &act, NULL); (void)::sigaction(SIGQUIT, &act, NULL); (void)::sigaction(SIGALRM, &act, NULL);}

同時在main函數中還有以下一段代碼,如果是父進程,則會阻塞在wait函數調用處,知道wait返回。wait函數的解釋是:父進程一旦調用了wait就立即阻塞自己,由wait自動分析是否當前進程的某個子進程已經退出,如果讓它找到了這樣一個已經變成殭屍的子進程,wait就會收集這個子進程的信息,並把它徹底銷燬後返回;如果沒有找到這樣一個子進程,wait就會一直阻塞在這裡,直到有一個出現為止。

int main(int argc, char * argv[]) { ... int status = 0; int pid = 0; pid_t processID = 0;  if ( !dontFork) // if (fork)  { //loop until the server exits normally. If the server doesn't exit //normally, then restart it. // normal exit means the following // the child quit  do // fork at least once but stop on the status conditions returned by wait or if autoStart pref is false { processID = fork(); Assert(processID >= 0); if (processID > 0) // this is the parent and we have a child { sChildPID = processID; status = 0; while (status == 0) //loop on wait until status is != 0; {  pid =::wait(&status); SInt8 exitStatus = (SInt8) WEXITSTATUS(status); //qtss_printf("Child Process %d wait exited with pid=%d status=%d exit status=%d\n", processID, pid, status, exitStatus);  if (WIFEXITED(status) && pid > 0 && status != 0) // child exited with status -2 restart or -1 don't restart  { //qtss_printf("child exited with status=%d\n", exitStatus);  if ( exitStatus == -1) // child couldn't run don't try again { qtss_printf("child exited with -1 fatal error so parent is exiting too.\n"); exit (EXIT_FAILURE);  } break; // restart the child  }  if (WIFSIGNALED(status)) // child exited on an unhandled signal (maybe a bus error or seg fault) {  //qtss_printf("child was signalled\n"); break; // restart the child }  if (pid == -1 && status == 0) // parent woken up by a handled signal { //qtss_printf("handled signal continue waiting\n"); continue; }  if (pid > 0 && status == 0) { //qtss_printf("child exited cleanly so parent is exiting\n"); exit(EXIT_SUCCESS);  }  //qtss_printf("child died for unknown reasons parent is exiting\n"); exit (EXIT_FAILURE); } } else if (processID == 0) // must be the child break; else exit(EXIT_FAILURE);   //eek. If you auto-restart too fast, you might start the new one before the OS has //cleaned up from the old one, resulting in startup errors when you create the new //one. Waiting for a second seems to work sleep(1); } while (RestartServer(theXMLFilePath)); // fork again based on pref if server dies if (processID != 0) //the parent is quitting exit(EXIT_SUCCESS);   } ...}

每天會更新論文和視頻,還有如果想學習c++知識在晚上8.30免費觀看這個直播:https://ke.qq.com/course/131973#tuin=b52b9a80


分享到:


相關文章: