Index: qs_qs1rio.cpp =================================================================== --- qs_qs1rio.cpp (revisione 643) +++ qs_qs1rio.cpp (copia locale) @@ -617,7 +617,7 @@ } // LOAD FIRMWARE FILE -#if defined __linux +#if defined __linux || defined __MINGW32__ FILE *f = fopen(filename.c_str(), "r"); if ((f = fopen(filename.c_str(), "r")) == 0) #else @@ -698,7 +698,7 @@ return false; } -#if defined __linux +#if defined __linux || defined __MINGW32__ FILE *f;; if ((f = fopen (filename.c_str(), "rb")) == 0) #else Index: daemon.h =================================================================== --- daemon.h (revisione 643) +++ daemon.h (copia locale) @@ -6,13 +6,51 @@ struct DaemonImp; class Daemon { +protected: + Daemon () {} public: - Daemon (); - ~Daemon (); - void daemonize ( const char *lockfile ); + virtual ~Daemon () {} + virtual void daemonize ( const char *lockfile ) = 0; + virtual int toBeDaemonized () = 0; + void run (); + static Daemon *create (); + static Daemon *pS; private: DaemonImp *pImp; }; +class DaemonLinux: public Daemon { +public: + DaemonLinux (); + virtual ~DaemonLinux (); + virtual void daemonize ( const char *lockfile ); + virtual int toBeDaemonized (); +private: + DaemonImp *pImp; +}; + +class DaemonWin32: public Daemon { +public: + DaemonWin32 (); + virtual ~DaemonWin32 (); + virtual void daemonize ( const char *lockfile ); + virtual int toBeDaemonized (); +protected: + // + // TBD + // Win32 platform specific + // to be implemented if we need to autoregister to Windows Services subsystem + // + int registerService (); + int unRegisterService (); +public: + // Needs to be declared public because there is not method to pass + // instance data to service main procedure + DaemonImp *pImp; +}; + + + + #endif Index: qs_constants.h =================================================================== --- qs_constants.h (revisione 643) +++ qs_constants.h (copia locale) @@ -26,7 +26,7 @@ #ifndef _QSCONSTANTS_H #define _QSCONSTANTS_H -#define APPVER "2.2.0.4" +#define APPVER "2.2.0.4_mingw_service" #define INI_FILENAME "qs1rserver.ini" #define FIRMWARE_FILENAME "qs1r_revc_firmware_03082008_1.hex" #define FPGA_FILENAME "qs1r_1ch_s.rbf" Index: main.cpp =================================================================== --- main.cpp (revisione 643) +++ main.cpp (copia locale) @@ -66,72 +66,67 @@ cout << endl; } +void Daemon :: run () +{ + boost::thread * cmdThreadRemote; + boost::thread * cmdThreadLocal; + QSRemoteCommandServer * cmdLoopRemote = new QSRemoteCommandServer(); + QSControl * qs1r = QSControl::Instance(); + + // find and load QS1R + // TBD: because a real server must wait for the hardware to come up + // we should use a loop here + // + qs1r->loadQS1R(); + + // start remote loop in a separate thread + // + if (!cmdLoopRemote->isRunning()) + cmdThreadRemote = new boost::thread(boost::bind(&QSRemoteCommandServer::run, cmdLoopRemote)), + cmdThreadRemote->join(); + + // the control never gets here + cout << "Daemon::run() exiting...." << endl; + return ; + +} + int main( int argc, char* argv[] ) { ShowInitialMessage(); - boost::thread * cmdThreadLocal; - boost::thread * cmdThreadRemote; + //boost::thread * cmdThreadLocal; + //boost::thread * cmdThreadRemote; - QSCommandLoopLocal * cmdLoopLocal = QSCommandLoopLocal::Instance(); - QSRemoteCommandServer * cmdLoopRemote = new QSRemoteCommandServer(); - QSControl * qs1r = QSControl::Instance(); + //QSCommandLoopLocal * cmdLoopLocal = QSCommandLoopLocal::Instance(); + //QSRemoteCommandServer * cmdLoopRemote = new QSRemoteCommandServer(); + //QSControl * qs1r = QSControl::Instance(); - // NOTE: NEEDS CHECKED FOR LINUX/OSX - if (argc > 0) - { - string path = argv[0]; + // NOTE: NEEDS CHECKED FOR LINUX/OSX + if (argc > 0) { + string path = argv[0]; #if __linux - // - // Get the real path to executables - // A.M. IW0HDV - // - char xPath[PATH_MAX+1] = {0}; - readlink("/proc/self/exe", xPath, sizeof(xPath)); - path = xPath; + // + // Get the real path to executables + // A.M. IW0HDV + // + char xPath[PATH_MAX+1] = {0}; + readlink("/proc/self/exe", xPath, sizeof(xPath)); + path = xPath; #endif - size_t pos = path.find_last_of("/\\"); - APPPATH = path.substr(0, pos + 1); - APPNAME = path.substr(pos + 1); + size_t pos = path.find_last_of("/\\"); + APPPATH = path.substr(0, pos + 1); + APPNAME = path.substr(pos + 1); } cout << APPPATH << endl; cout << APPNAME << endl; - const char *pszDaemonFlag = 0; + Daemon *pd = Daemon::create(); - if (( pszDaemonFlag = getenv("DAEMON")) && (strcmp(pszDaemonFlag, "1") == 0) ) { + if ( pd && pd->toBeDaemonized() ) { + pd->daemonize ("QS1RServer"); - Daemon d; - d.daemonize ("/var/lock/" "QS1RServer"); - - boost::thread * cmdThreadRemote; - - QSRemoteCommandServer * cmdLoopRemote = new QSRemoteCommandServer(); - - QSControl * qs1r = QSControl::Instance(); - - // find and load QS1R - // TBD: because a real server must wait for the hardware to come up - // we should use a loop here - // - qs1r->loadQS1R(); - - // start remote loop in a separate thread - // - if (!cmdLoopRemote->isRunning()) - cmdThreadRemote = new boost::thread(boost::bind(&QSRemoteCommandServer::run, cmdLoopRemote)); - -#if defined __linux - while (1) { - sleep(1000); - } -#else - while (1) { - Sleep(1000 * 1000); - } -#endif - } else { boost::thread * cmdThreadLocal; @@ -157,17 +152,18 @@ // stop the remote loop if local command loop exits cmdLoopRemote->stop(); ShowFinalMessage( ); - } #if !defined __linux + cout << "Press ENTER key to close server..." << endl; - cout << "Press ENTER key to close server..." << endl; - char buffer[10]; cin.getline(buffer, sizeof(buffer)); - #endif + } + + + return ( EXIT_SUCCESS ); } Index: daemon.cpp =================================================================== --- daemon.cpp (revisione 643) +++ daemon.cpp (copia locale) @@ -1,27 +1,34 @@ #include #include #include +#include +#include +#include "daemon.h" + #if defined __linux #include #include #include -#endif #include #include #include #include #include -#include -#include -#include "daemon.h" +/* Change this to the user under which to run */ +#define RUN_AS_USER "daemon" + +#endif + +#if defined _WIN32 +#include +#endif + using namespace std; /* Change this to whatever your daemon is called */ #define DAEMON_NAME "QS1RServer" -/* Change this to the user under which to run */ -#define RUN_AS_USER "daemon" #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 @@ -44,7 +51,9 @@ protected: static const int bufferSize = BUFSIZ; // size of data buffer char buffer[bufferSize]; // data buffer - + #if defined _WIN32 + FILE *pF; + #endif public: /* constructor * - initialize data buffer @@ -56,7 +65,7 @@ #if defined __linux || defined __APPLE__ openlog( DAEMON_NAME, LOG_PID, LOG_LOCAL5 ); #elif defined _WIN32 - // TBD WIN32 + pF = fopen ("\\windows\\temp\\qs1rserver.log", "w"); #endif } @@ -75,7 +84,10 @@ #if defined __linux || defined __APPLE__ syslog (LOG_INFO, "%.*s", num, buffer ); #elif defined _WIN32 - // TBD WIN32 + if (pF) { + fwrite (buffer, 1, num, pF); + fflush (pF); + } #endif pbump (-num); // reset put pointer accordingly @@ -111,6 +123,23 @@ } }; +Daemon * Daemon :: create () +{ + if (Daemon :: pS == 0) { + #if defined __linux || defined __APPLE__ + Daemon :: pS = new DaemonLinux; + #elif defined _WIN32 + Daemon :: pS = new DaemonWin32; + #else + #error Platform undefined !!! + #endif + } + return Daemon::pS; +} + +Daemon * Daemon :: pS = 0; + + #if defined __linux || defined __APPLE__ static void child_handler(int signum) @@ -129,7 +158,7 @@ }; -Daemon :: Daemon () +DaemonLinux :: DaemonLinux () { pImp = new DaemonImp; if (pImp) { @@ -138,7 +167,7 @@ } -Daemon :: ~Daemon () +DaemonLinux :: ~DaemonLinux () { pImp = new DaemonImp; if (pImp) { @@ -185,12 +214,17 @@ * */ -void Daemon::daemonize( const char *lockfile ) +void DaemonLinux::daemonize( const char *fn ) { - pid_t pid, sid, parent; + pid_t pid, sid, parent; - /* already a daemon */ - if ( getppid() == 1 ) return; + /* If is already a daemon skip the daemonization process */ + if ( ! (getppid() == 1) ) { + + char lockfile [BUFSIZ] = "/var/lock/"; + if (fn && strlen(fn) && fn[0] != '/') + strcat (lockfile, fn); + else if (fn && strlen(fn)) strcpy (lockfile, fn); syslog( LOG_INFO, "Before getuid" ); /* Drop user if there is one, and we were run as root */ @@ -279,8 +313,7 @@ freopen( "/dev/null", "w", stdout); freopen( "/dev/null", "w", stderr); - syslog( LOG_INFO, "Child process before redirect standard streams"); - + } //pImp->outputFileStream.open ("/tmp/qs1rserver.log"); //pImp->logStreamBuffer = pImp->outputFileStream.rdbuf(); cout.rdbuf(pImp->logStreamBuffer); @@ -291,13 +324,227 @@ kill( parent, SIGUSR1 ); syslog( LOG_INFO, "Child process exiting from daemonize"); + + run(); } +int DaemonLinux :: toBeDaemonized () +{ + char *pszDaemonFlag = 0; + return ((pszDaemonFlag = getenv("DAEMON")) != 0) + && + (strcmp(pszDaemonFlag, "1") == 0) + ; +} -#if defined TEST_MODULE +#elif defined _WIN32 + + +struct DaemonImp { + streambuf * logStreamBuffer; + ofstream outputFileStream; + // + char * pszServiceName; + SERVICE_STATUS serviceStatus; + SERVICE_STATUS_HANDLE serviceStatusHandle; +}; + +void WINAPI QS1RServiceCtrlHandler(DWORD Opcode); + +void WINAPI QS1RServiceStart (DWORD /* argc */, LPTSTR * /* argv */ ) +{ + + DWORD status; + + struct DaemonImp * pImp = ((DaemonWin32 *)(Daemon :: pS))->pImp; + + std::cout << "QS1RServiceStart" << std::endl; + + // Type of service, application or driver... + pImp->serviceStatus.dwServiceType = SERVICE_WIN32; + + // The service is starting... + pImp->serviceStatus.dwCurrentState = SERVICE_START_PENDING; + + // The service can be stopped & can be paused and continued. + pImp->serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; + pImp->serviceStatus.dwWin32ExitCode = 0; + pImp->serviceStatus.dwServiceSpecificExitCode = 0; + pImp->serviceStatus.dwCheckPoint = 0; + pImp->serviceStatus.dwWaitHint = 0; + + pImp->serviceStatusHandle = RegisterServiceCtrlHandler ("QS1RService", QS1RServiceCtrlHandler); + + if (pImp->serviceStatusHandle == (SERVICE_STATUS_HANDLE)0) { + std::cout << "RegisterServiceCtrlHandler() failed, error: " << ((int)GetLastError()) << std::endl; + return; + } else + std::cout << "RegisterServiceCtrlHandler() looks OK." << std::endl; + +#if 0 + // Initialization code goes here...return the status... + status = MyServiceInitialization (argc, argv, &specificError); + + // Handle error condition + if (status != NO_ERROR) { + + // The service is not running... + pImp->serviceStatus.dwCurrentState = SERVICE_STOPPED; + pImp->serviceStatus.dwCheckPoint = 0; + pImp->serviceStatus.dwWaitHint = 0; + pImp->serviceStatus.dwWin32ExitCode = status; + pImp->serviceStatus.dwServiceSpecificExitCode = specificError; + SetServiceStatus(pImp->serviceStatusHandle, &(pImp->serviceStatus)); + + return; + } + #endif + + // Initialization complete - report running status. + pImp->serviceStatus.dwCurrentState = SERVICE_RUNNING; + pImp->serviceStatus.dwCheckPoint = 0; + pImp->serviceStatus.dwWaitHint = 0; + + if (!SetServiceStatus (pImp->serviceStatusHandle, &(pImp->serviceStatus))) { + status = GetLastError(); + std::cout << "SetServiceStatus() error: " << status << std::endl; + } else + std::cout << "SetServiceStatus() looks OK.\n"; + + // This is where the service does its work... + ((DaemonWin32 *)(Daemon :: pS))->run(); + + std::cout << "Returning the Main Thread." << std::endl; + return; +} + +// +// Handler function - receives Opcode, calls SetServiceStatus() +// +void WINAPI QS1RServiceCtrlHandler(DWORD Opcode) +{ + struct DaemonImp * pImp = ((DaemonWin32 *)(Daemon :: pS))->pImp; + + std::cout << "QS1RServiceCtrlHandler opcode: " << Opcode << std::endl; + + DWORD status; + switch(Opcode) { + case SERVICE_CONTROL_PAUSE: + std::cout << "QS1RServiceCtrlHandler SERVICE_CONTROL_PAUSE" << std::endl; + // Do whatever it takes to pause here... + pImp->serviceStatus.dwCurrentState = SERVICE_PAUSED; + break; + + case SERVICE_CONTROL_CONTINUE: + std::cout << "QS1RServiceCtrlHandler SERVICE_CONTROL_CONTINUE" << std::endl; + // Do whatever it takes to continue here... + pImp->serviceStatus.dwCurrentState = SERVICE_RUNNING; + break; + + case SERVICE_CONTROL_STOP: + std::cout << "QS1RServiceCtrlHandler SERVICE_CONTROL_STOP" << std::endl; + // Do whatever it takes to stop here... + pImp->serviceStatus.dwWin32ExitCode = 0; + pImp->serviceStatus.dwCurrentState = SERVICE_STOPPED; + pImp->serviceStatus.dwCheckPoint = 0; + pImp->serviceStatus.dwWaitHint = 0; + if (!SetServiceStatus (pImp->serviceStatusHandle, &(pImp->serviceStatus))) { + status = GetLastError(); + std::cout << "SetServiceStatus() error: " << status << std::endl; + } + std::cout << "Leaving service." << std::endl; + return; + + case SERVICE_CONTROL_INTERROGATE: + std::cout << "QS1RServiceCtrlHandler SERVICE_CONTROL_INTERROGATE" << std::endl; + // Fall through to send current status. + break; + + default: + // else + std::cout << "Unrecognized opcode: " << Opcode << std::endl; + } + + // Send current status. + if (!SetServiceStatus(pImp->serviceStatusHandle, &(pImp->serviceStatus))) { + status = GetLastError(); + std::cout << "SetServiceStatus error: " << status << std::endl; + return; + } else + std::cout << "SetServiceStatus() is OK." << std::endl; +} + + + + +DaemonWin32 :: DaemonWin32 () +{ + pImp = new DaemonImp; + if (pImp) { + pImp->logStreamBuffer = new logbuf; + } +} + + +DaemonWin32 :: ~DaemonWin32 () +{ + pImp = new DaemonImp; + if (pImp) { + delete pImp; + } +} + +void DaemonWin32::daemonize( const char * /*serviceName*/ ) +{ + SERVICE_TABLE_ENTRY DispatchTable[] = {{(CHAR *)"QS1RServer", QS1RServiceStart}, {NULL, NULL}}; + + struct DaemonImp * pImp = ((DaemonWin32 *)(Daemon :: pS))->pImp; + + // save console streambuf + streambuf *pSsb = cout.rdbuf (); + // detach cout from console + cout.rdbuf (pImp->logStreamBuffer); + + int rc = StartServiceCtrlDispatcher (DispatchTable); + + if (!rc) { + + // restore cout on console + cout.rdbuf (pSsb); + + if (rc != 1063) std::cout << "StartServiceCtrlDispatcher() failed, error: " + << ((int)GetLastError()) + << "." + << std::endl ; + } else { + std::cout << "StartServiceCtrlDispatcher() looks OK" << std::endl; + } + return; +} + + +int DaemonWin32 :: toBeDaemonized () +{ + // + // it seems there doesn't exists a technique to discover for sure + // if we have been launched from SCM + // + + // check for service into executable name + return ( strstr (_argv[0], "_service") != NULL ); +} + + + +#endif + + + +#if defined TEST_MODULE && ( defined __linux || defined __APPLE__ ) + pthread_mutex_t m; @@ -315,8 +562,6 @@ /* Daemonize */ daemonize( "/var/lock/" DAEMON_NAME ); - //cout << "GRRRRRRRRRRRRRRRRRRRRRRRR" << endl; - int const res=pthread_mutex_init(&m,NULL); if (res) { syslog (LOG_ERR, "thread_resource_error"); @@ -343,34 +588,3 @@ #endif - -#elif defined _WIN32 - -struct DaemonImp { -}; - - -Daemon :: Daemon () -{ - pImp = new DaemonImp; - if (pImp) { - //TBD - } -} - - -Daemon :: ~Daemon () -{ - pImp = new DaemonImp; - if (pImp) { - delete pImp; - } -} - -void Daemon::daemonize( const char *lockfile ) -{ - // TBD -} - - -#endif