www.pudn.com > vls-0.5.6.rar > application.cpp


/*******************************************************************************
* application.cpp: Application class
*-------------------------------------------------------------------------------
* (c)1999-2004 VideoLAN
* $Id: application.cpp,v 1.17.4.6 2004/01/10 21:54:57 alexis Exp $
*
* Authors: Benoit Steiner 
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
*-------------------------------------------------------------------------------
* The C_Application class provides some core mecanisms for applications, such
* as a global logging service
*
*******************************************************************************/

#define COPYRIGHT \
"VideoLAN Server - version 0.5.5 - (c)1996-2004 VideoLAN\n"

#define VERSION \
  COPYRIGHT \
  "\n" \
  "This program comes with NO WARRANTY, to the extent permitted by law.\n" \
  "You may redistribute it under the terms of the GNU General Public " \
  "License;\n" \
  "see the file named COPYING for details.\n" \
  "Written by the VideoLAN team at Ecole Centrale, Paris.\n"

#define HELP \
  COPYRIGHT \
  "\n" \
  " vls [options] target\n" \
  " \n" \
  " options: \n" \
  "                       --version      display version and exit\n" \
  "   -v                  --verbose      verbosity (v, vv, vvv)\n" \
  "   -h                  --help         display this help\n" \
  "   -d          --destination  output \n" \
  "   -f            --file   configuration file\n" \
  "   -t          --ttl  ttl value\n" \
  "   -l                  --loop         looping at end of program\n" \
  "                       --log    log to  \n" \
  " \n" \
  " target:\n" \
  "   dvd:     for streaming from a dvd\n" \
  "   dvd:        for streaming from a dvd stored on hard drive\n" \
  "   file:      for streaming from a file\n" \
  "   dvb:    for streaming from a dvb channel\n" \
  "   udp:  for streaming in udp to ip \n" \
  "   rtp:  for streaming in rtp to ip \n" \
  "   file:  for dumping output to filename \n"

//------------------------------------------------------------------------------
// Preamble
//------------------------------------------------------------------------------
#include "defs.h"

#include 
#include 
#include 
#ifdef HAVE_OPENDIR
#include 
#endif
#include 
#include 
#ifdef SYSLOG
#include 
#endif
#ifdef HAVE_GETOPT_H
#  include                                             /* getopt() */
#else
#  ifdef WIN32
#    define __STDC__ 1
#  endif
#  include "../extras/getopt.h"
#endif

#include "common.h"
#include "debug.h"
#include "reflect.h"
#include "serialization.h"
#include "string.h"
#include "stack.h"
#include "vector.h"
#include "hashtable.h"
#include "buffers.h"
#include "exception.h"
#include "file.h"
#include "stream.h"
#include "parsers.h"
#include "settings.h"
#include "log.h"
#include "library.h"
#include "module.h"
#include "application.h"


#include "stack.cpp"
#include "vector.cpp"
#include "hashtable.cpp"
#include "library.cpp"


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
C_Application* C_Application::s_pApplication = NULL;


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
C_Application::C_Application(const C_String& strName) : m_strName(strName)
{
  ASSERT(s_pApplication == NULL);
  s_pApplication = this;

  m_hLog = NULL;

  m_pModuleManager = NULL;

  m_bOnStop = false;

  m_iLogFlags = LOG_ERRORMSG;
}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
C_Application::~C_Application()
{
  ASSERT(this == s_pApplication);
  s_pApplication = NULL;

  delete m_pModuleManager;
}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
int C_Application::Init(int iArgc, char* paArg[])
{
  // Retrieve global configuration from cmd line and cfg file
  // Shortly, this step will build a properties table
  int iRc = RetrieveConfig(iArgc, paArg);

  // Init the logger
  if(!iRc)
  {
    C_String strLogFileSetting = "Global.LogFile";
    C_String strLogFile = GetSetting(strLogFileSetting, "");

    if (strLogFile != "")
    {
      iRc     |= m_cLog.Init(strLogFile);
      m_iLogFlags |= LOG_FILE;
    }
  }

  // Check if System Logging is enabled in the vls.cfg
  C_String strSystemLog = GetSetting("Global.SystemLog", "disable");

  if (strSystemLog == "enable")
    m_iLogFlags |= LOG_SYSTEM;

  // Check if screen Logging is enabled in the vls.cfg
  C_String strScrLog = GetSetting("Global.ScreenLog", "enable");

  if (strScrLog == "enable")
    m_iLogFlags |= LOG_SCR;

  // Register the application object by the logger
  if(!iRc)
  {
    m_hLog = StartLog(m_strName, m_iLogFlags );
    if(!m_hLog)
      iRc = GEN_ERR;
  }

  // First install the signal handler
  if(!iRc)
    iRc = InstallSigHandler();

  // Create the module manager
  m_pModuleManager = new C_ModuleManager(m_hLog);

  // Do application specific initialisations
  if(!iRc)
    iRc = OnAppInit();

  return iRc;
}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
int C_Application::Run()
{
  return OnAppRun();
}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
int C_Application::Stop()
{
  if(!m_bOnStop)
  {
    m_bOnStop = true;
    return OnAppExit();
  }
  else return GEN_ERR;
}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
int C_Application::Destroy()
{
  int iRc = OnAppDestroy();
  
  if(!iRc)
  {
    if(m_hLog)
      StopLog(m_hLog);
    iRc = m_cLog.End();
  }

  return iRc;
}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
handle C_Application::StartLog(const C_String& strClientDescr, u8 iFlags)
{
  handle hLog = m_cLog.Register(strClientDescr, iFlags);
  ASSERT(hLog);

  // Init the syslog
  if (iFlags & LOG_SYSTEM)
  {
#ifdef SYSLOG
    openlog("vls", LOG_NOWAIT | LOG_NDELAY | LOG_PID, LOG_USER);
#endif
  }

  return hLog;
}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
void C_Application::StopLog(handle hLog)
{
  ASSERT(hLog);

  // close the syslog
  if (m_iLogFlags & LOG_SYSTEM)
  {
#ifdef SYSLOG
    closelog();
#endif
  }

  m_cLog.Unregister(hLog);

}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
void C_Application::LogMsg(handle hLog, int iLevel, const C_String& strMsg)
{ 
  if(hLog)
  {
    // Use the given handle to log
    m_cLog.Append(hLog, iLevel, strMsg);
  }
  else
  {
    // Use the application handle to log
    m_cLog.Append(m_hLog, iLevel, strMsg);
  }
}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
int C_Application::InstallSigHandler()
{
  int iRc = NO_ERR;

#ifdef HAVE_SIGACTION
  sigset_t sSigSet;
  sigemptyset(&sSigSet);
  struct sigaction sSigAction;
  sSigAction.sa_mask = sSigSet;
  sSigAction.sa_flags = 0;
  //sSigAction.sa_restorer = NULL;

  sSigAction.sa_handler = SignalHandler;
  if(sigaction(SIGHUP, &sSigAction, NULL) != 0)
  {
    Log(m_hLog, LOG_ERROR, "Could not install handler for signal SIG_HUP");
    iRc |= 1;
  }

  sSigAction.sa_handler = SignalHandler;
  if(sigaction(SIGINT, &sSigAction, NULL) != 0)
  {
    Log(m_hLog, LOG_ERROR, "Could not install handler for signal SIG_INT");
    iRc |= 1;
  }

  sSigAction.sa_handler = SignalHandler;
  if(sigaction(SIGQUIT, &sSigAction, NULL) != 0)
  {
    Log(m_hLog, LOG_ERROR, "Could not install handler for signal SIG_QUIT");
    iRc |= 1;
  }

  sSigAction.sa_handler = SignalHandler;
  if(sigaction(SIGPIPE, &sSigAction, NULL) != 0)
  {
    Log(m_hLog, LOG_ERROR, "Could not install handler for signal SIG_PIPE");
    iRc |= 1;
  }

  sSigAction.sa_handler = SignalHandler;
  if(sigaction(SIGURG, &sSigAction, NULL) != 0)
  {
    Log(m_hLog, LOG_ERROR, "Could not install handler for signal SIG_URG");
    iRc |= 1;
  }

  // Don't catch the signal if we are in debug mode unless we wouldn't get a core file
#ifndef DEBUG
  sSigAction.sa_handler = SignalHandler;
  if(sigaction(SIGSEGV, &sSigAction, NULL) != 0)
  {
    Log(m_hLog, LOG_ERROR, "Could not install handler for signal SIG_SEGV");
    iRc |= 1;
  }
#endif

  sSigAction.sa_handler = SignalHandler;
  if(sigaction(SIGTERM, &sSigAction, NULL) != 0)
  {
    Log(m_hLog, LOG_ERROR, "Could not install handler for signal SIG_TERM");
    iRc |= 1;
  }
#endif

  return iRc;
}


//------------------------------------------------------------------------------
// 
//------------------------------------------------------------------------------
int C_Application::RetrieveConfig(int iArgc, char* paArg[])
{
  C_String strCfgFile;
  C_String strDest;
  int iRc = NO_ERR;
  int iCommandline=0;
  int opt;

  C_String strName = m_strName.ToLower() + ".cfg";

 #ifndef _WIN32
   strCfgFile = CONFIG_PATH "/" + strName;
 #else
   strCfgFile = strName;
 #endif
 
  static const struct option longopts[]={
    {"verbose", 0 , 0 , 'v'},
    {"help", 0 , 0, 'h'},
    {"file", 1, 0, 'f'},
    {"version", 0, 0, 129},
    {"destination", 1, 0,'d'},
    {"ttl", 1, 0, 't'},
    {"loop", 0,0, 'l'},
    {"log", 1, 0, 130},
    {0,0,0,0}
  };
  static char shortopts[]="f:d:hvt:l";
  
  //Parse command line options
  while((opt = getopt_long(iArgc, paArg, shortopts, longopts, 0)) != EOF)
  {
    switch(opt)
    {
      case 'v':
       if(m_iLogFlags&LOG_NOTEMSG) m_iLogFlags |= LOG_DBGMSG; 
       if(m_iLogFlags&LOG_WARNMSG) m_iLogFlags |= LOG_NOTEMSG; 
       if(m_iLogFlags&LOG_ERRORMSG) m_iLogFlags |= LOG_WARNMSG; 
       break;

      case 129:
       printf(VERSION);
       exit(0);
       break;

      case 'f':
       strCfgFile = optarg;
       break;

      case 'h':
       printf(HELP);
       exit(0);

      default:
       if(optarg!=NULL)
         m_cSettings.AddCmdLineSetting(opt,C_String(optarg));
       else
         m_cSettings.AddCmdLineSetting(opt,"");
       break;
       
    }
  }
  if(optindm_hLog;

  switch(iSignal)
  {
    case SIGHUP:
    {
      Log(hLog, LOG_WARN, "Received SIGHUP: Hangup detected");
      break;
    }
    case SIGINT:
    {
      Log(hLog, LOG_WARN,
          "Received SIGINT: Interrupt from keyboard, launching shutdown sequence...");
      pApp->Stop();
      break;
    }
    case SIGQUIT:
    {
      Log(hLog, LOG_WARN,
          "Received SIGQUIT: Quit from keyboard, launching shutdown sequence...");
      pApp->Stop();
      break;
    }
    case SIGTERM:
    {
      Log(hLog, LOG_WARN,
          "Received SIGTERM: Software termination signal, launching shutdown sequence...");
      pApp->Stop();
      break;
    }
    case SIGSEGV:
    {
      Log(hLog, LOG_WARN,
          "Received SIGSEGV: Segmentation Violation, exiting...");
      exit(1);
      break;
    }
    case SIGPIPE:
    {
      // This signal is sent upon attempt to write on a broken stream
      // (such as a dead socket)
      Log(hLog, LOG_WARN, "Received SIGPIPE: Unexpected Broken Pipe encountered");
      break;
    }
    case SIGURG:
    {
      // This signal is sent when AOB data is received on a TCP connection
      Log(hLog, LOG_NOTE, "Received SIGURG: unexpected AOB data received");
      break;
    }
    default:
    {
      Log(hLog, LOG_NOTE, "Received signal " + iSignal);
      break;
    }
  }
#endif
}