00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "daemon.h"
00025 #include "daemon_windows.h"
00026 #include "main.h"
00027
00028 #define NEED_PACKAGE_INFO
00029 #ifdef HAVE_CONFIG_H
00030 # include "config.h"
00031 #endif
00032
00033 using namespace std;
00034
00035 #include <fstream>
00036 #include <stdlib.h>
00037 #include <errno.h>
00038 #include <string>
00039 #include <vector>
00040
00041 #define AS_STR_2(x) #x
00042 #define AS_STR_1(x) AS_STR_2(x)
00043
00044 #define HERE __FILE__ ":" AS_STR_1(__LINE__)
00045
00046
00047 namespace omniORB {
00048 void setLogFunction(void (*logFunction)(const char*));
00049 }
00050
00051 namespace OmniEvents {
00052
00054 class Win
00055 {
00056 public:
00057 static const char* strerror(DWORD e)
00058 {
00059 LPVOID buf;
00060 ::FormatMessage(
00061 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00062 NULL,
00063 e,
00064 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
00065 (LPTSTR)&buf,
00066 0, NULL
00067 );
00068 return (const char*)(buf);
00069 }
00070
00071 static void perror(const char* s=NULL)
00072 {
00073 if(s)
00074 {
00075 Service::log(s);
00076 Service::log(": ");
00077 }
00078 Service::log(Win::strerror(::GetLastError()));
00079 }
00080 };
00081
00086 class RegistryKey
00087 {
00088 HKEY _hkey;
00089 bool _open;
00090 private:
00091 RegistryKey();
00092 RegistryKey(HKEY hkey, bool open=true):_hkey(hkey),_open(open){}
00093 public:
00094 RegistryKey(RegistryKey& right);
00095 RegistryKey(HKEY hkey, const char* subkey, REGSAM samDesired=KEY_QUERY_VALUE);
00096 ~RegistryKey();
00097 operator bool() const { return _open; }
00098 int setValueStr(const char* name, const char* data);
00099 char* queryValueStr(const char* name, const int maxlen=2048) const;
00100 };
00101
00103 RegistryKey::RegistryKey(RegistryKey& right):
00104 _hkey(right._hkey),_open(right._open)
00105 {
00106 right._open=false;
00107 }
00108
00110 RegistryKey::RegistryKey(
00111 HKEY hkey,
00112 const char* subkey,
00113 REGSAM samDesired
00114 ):_hkey(), _open(false)
00115 {
00116 long ret=::RegOpenKeyEx(hkey,subkey,0,samDesired,&_hkey);
00117 ::SetLastError(ret);
00118 if(ret==ERROR_SUCCESS)
00119 _open=true;
00120 }
00121
00123 RegistryKey::~RegistryKey()
00124 {
00125
00126
00127 if(_open)
00128 {
00129 long ret =::RegCloseKey(_hkey);
00130 ::SetLastError(ret);
00131 if(ret!=ERROR_SUCCESS)
00132 Win::perror("Warning at " HERE);
00133 }
00134 }
00135
00136 int RegistryKey::setValueStr(const char* name, const char* data)
00137 {
00138 long ret=::RegSetValueEx(
00139 _hkey,name,0,REG_SZ,
00140 (const BYTE*)(data),
00141 1+::strlen(data)
00142 );
00143 ::SetLastError(ret);
00144 if(ret==ERROR_SUCCESS)
00145 return 0;
00146 else
00147 return 1;
00148 }
00149
00150 char* RegistryKey::queryValueStr(const char* name, const int maxlen) const
00151 {
00152 char* result =NULL;
00153 char* buf =new char[maxlen];
00154 DWORD len =maxlen;
00155
00156 long ret=::RegQueryValueEx(_hkey,name,NULL,NULL,(LPBYTE)buf,&len);
00157 ::SetLastError(ret);
00158 if(ret==ERROR_SUCCESS && len<=maxlen)
00159 result=::strdup(buf);
00160 delete[] buf;
00161 return result;
00162 }
00164
00166 static Service service;
00167
00168 Daemon::Daemon(int& argc,char**& argv) { service.start(argc,argv); }
00169 void Daemon::tracefile(const char* val) { service.tracefile(val); }
00170 void Daemon::pidfile(const char* val) { service.pidfile(val); }
00171 void Daemon::foreground(bool val) { service.foreground(val); }
00172 void Daemon::daemonize() { service.daemonize(); }
00173 void Daemon::runningOk() { service.runningOk(); }
00174 Daemon::~Daemon() { service.shutdown(); }
00175
00176 void shutdown0(void){ service.shutdown(); }
00177
00179
00180 Service::Service():
00181 _tracefile(NULL),
00182 _regSubKey("SYSTEM\\CurrentControlSet\\Services\\" PACKAGE_NAME),
00183 _serviceRunning(false),
00184 _callCount(0),
00185 _parameters(NULL),
00186 _argv(NULL),
00187 _logstream(&cerr),
00188 _serviceStatusHandle()
00189 {}
00190
00191
00192 Service::~Service()
00193 {
00194 delete[] _tracefile;
00195 delete[] _parameters;
00196 delete[] _argv;
00197 if(_logstream!=&cerr)
00198 delete _logstream;
00199 }
00200
00201
00202 void Service::tracefile(const char* val)
00203 {
00204 delete[] _tracefile;
00205 _tracefile=::strdup(val);
00206 }
00207
00208
00209 void Service::pidfile(const char* val)
00210 {
00211 Service::log("Option -P not supported on windows.\n");
00212 ::exit(1);
00213 }
00214
00215
00216 void Service::foreground(bool val)
00217 {
00218 Service::log("Option -f not supported on windows.\n");
00219 ::exit(1);
00220 }
00221
00222
00223 void Service::start(int& argc,char**& argv)
00224 {
00225 ++_callCount;
00226 if(_callCount>1)
00227 {
00228
00229 setArgcArgv(argc,argv);
00230 _serviceStatusHandle=
00231 ::RegisterServiceCtrlHandler(
00232 PACKAGE_NAME,
00233 (LPHANDLER_FUNCTION)Service::ctrlHandler
00234 );
00235 if(!_serviceStatusHandle)
00236 ::exit(1);
00237 if(! setServiceStatus(SERVICE_START_PENDING,NO_ERROR,0,1,3000) )
00238 ::exit(1);
00239 _serviceRunning=true;
00240
00241 }
00242 else if(argc>=2 && 0==::strcmp(argv[1],"service"))
00243 {
00244
00245 char* name =::strdup(PACKAGE_NAME);
00246 SERVICE_TABLE_ENTRY servicetable[]=
00247 {
00248 {name,(LPSERVICE_MAIN_FUNCTION)::main},
00249 {NULL,NULL}
00250 };
00251 if(! ::StartServiceCtrlDispatcher(servicetable) )
00252 {
00253 Win::perror(HERE);
00254 ::exit(1);
00255 }
00256 ::exit(0);
00257 }
00258 else if(argc>=2 && 0==::strcmp(argv[1],"install"))
00259 {
00260 install(argc,argv);
00261 cout<<"Service '" PACKAGE_NAME "' installed OK."<<endl;
00262 ::exit(0);
00263 }
00264 else if(argc>=2 && 0==::strcmp(argv[1],"uninstall"))
00265 {
00266 uninstall();
00267 cout<<"Service '" PACKAGE_NAME "' removed."<<endl;
00268 ::exit(0);
00269 }
00270 else if(argc>=2 && 0==::strcmp(argv[1],"getoptions"))
00271 {
00272 readParameters();
00273 cout<<_parameters<<endl;
00274 ::exit(0);
00275 }
00276 else if(argc>=2 && 0==::strcmp(argv[1],"setoptions"))
00277 {
00278 writeParameters(argc,argv);
00279 ::exit(0);
00280 }
00281 else if(argc>=2 && 0==::strcmp(argv[1],"run"))
00282 {
00283 setArgcArgv(argc,argv);
00284 }
00285 else
00286 {
00287 ;
00288 }
00289 }
00290
00291
00292 void Service::daemonize()
00293 {
00294 if(_tracefile && _tracefile[0]!='\0')
00295 {
00296 _logstream=new ofstream(_tracefile,ios::out|ios::app);
00297 omniORB::setLogFunction(Service::log);
00298 }
00299
00300
00301 if( ::atexit(shutdown0) <0)
00302 {
00303 Service::log("Failed to set exit handler.");
00304 ::exit(-1);
00305 }
00306 }
00307
00308
00309 void Service::runningOk()
00310 {
00311 if(_serviceRunning)
00312 {
00313 if(! setServiceStatus(SERVICE_RUNNING,NO_ERROR,0,0,0) )
00314 ::exit(1);
00315 }
00316 }
00317
00318
00319 void Service::shutdown()
00320 {
00321 if(_logstream!=&cerr)
00322 {
00323 delete _logstream;
00324 _logstream=&cerr;
00325 }
00326 if(_serviceRunning)
00327 {
00328 setServiceStatus(SERVICE_STOPPED,NO_ERROR,0,0,0);
00329 _serviceRunning=false;
00330 }
00331 }
00332
00333
00334 void Service::log(const char* message)
00335 {
00336 (*service._logstream)<<message<<flush;
00337 }
00338
00339
00340 void Service::ctrlHandler(DWORD controlCode)
00341 {
00342 switch(controlCode)
00343 {
00344 case SERVICE_CONTROL_SHUTDOWN:
00345 case SERVICE_CONTROL_STOP:
00346 ::OmniEvents_Orb_shutdown(controlCode);
00347 service.setServiceStatus(SERVICE_STOP_PENDING,NO_ERROR,0,1,6000);
00348 break;
00349 case 128:
00350 ::OmniEvents_Orb_bumpTraceLevel(controlCode);
00351 break;
00352 default:
00353 break;
00354 }
00355 }
00356
00357
00358 void Service::setArgcArgv(int& argc,char**& argv)
00359 {
00360 readParameters();
00361 vector<char*> args;
00362 char* param =::strtok(_parameters,"\t ");
00363 while(param)
00364 {
00365 args.push_back(param);
00366 param=::strtok(NULL,"\t ");
00367 }
00368 if(!args.empty())
00369 {
00370 _argv=new char*[argc+args.size()];
00371 int i=0;
00372 _argv[i++]=argv[0];
00373 for(int j=0; j<args.size(); ++j)
00374 _argv[i++]=args[j];
00375 for(int k=1; k<argc; ++k)
00376 _argv[i++]=argv[k];
00377 argv=_argv;
00378 argc=i;
00379 }
00380 }
00381
00382
00383 void Service::install(int argc,char** argv) const
00384 {
00385
00386
00387 char exe_file_name[MAX_PATH];
00388 if(0== ::GetModuleFileName(0, exe_file_name, MAX_PATH) )
00389 {
00390 Win::perror(HERE);
00391 ::exit(1);
00392 }
00393
00394 string command =string(exe_file_name)+" service";
00395
00396 SC_HANDLE scmanager =::OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
00397 if(!scmanager)
00398 {
00399 Win::perror(HERE);
00400 ::exit(1);
00401 }
00402 SC_HANDLE service =
00403 ::CreateService(
00404 scmanager,
00405 PACKAGE_NAME,
00406 "CORBA Event Daemon",
00407 SERVICE_ALL_ACCESS,
00408 SERVICE_WIN32_OWN_PROCESS,
00409 SERVICE_AUTO_START,
00410 SERVICE_ERROR_NORMAL,
00411 command.c_str(),
00412 0,0,0,0,0
00413 );
00414 if(!service)
00415 {
00416 Win::perror(HERE);
00417 ::exit(1);
00418 }
00419 if(0== ::CloseServiceHandle(service) )
00420 {
00421 Win::perror(HERE);
00422 ::exit(1);
00423 }
00424 if(0== ::CloseServiceHandle(scmanager) )
00425 {
00426 Win::perror(HERE);
00427 ::exit(1);
00428 }
00429
00430
00431
00432 writeParameters(argc,argv);
00433 RegistryKey rkey(HKEY_LOCAL_MACHINE,_regSubKey,KEY_SET_VALUE);
00434 if(!rkey)
00435 {
00436 Win::perror("Can't open registry key at " HERE);
00437 ::exit(1);
00438 }
00439 if(0!= rkey.setValueStr("Description",
00440 "Asynchronous broadcast channels for CORBA applications.") )
00441 {
00442 Win::perror("Can't set registry value 'Description' at " HERE);
00443 ::exit(1);
00444 }
00445 }
00446
00447
00448 void Service::uninstall() const
00449 {
00450 SC_HANDLE scmanager =::OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
00451 if(!scmanager)
00452 {
00453 Win::perror(HERE);
00454 ::exit(1);
00455 }
00456 SC_HANDLE service =
00457 ::OpenService(
00458 scmanager,
00459 PACKAGE_NAME,
00460 SC_MANAGER_ALL_ACCESS
00461 );
00462 if(!service)
00463 {
00464 Win::perror(HERE);
00465 ::exit(1);
00466 }
00467 if(0== ::DeleteService(service) )
00468 {
00469 Win::perror(HERE);
00470 ::exit(1);
00471 }
00472 if(0== ::CloseServiceHandle(service) )
00473 {
00474 Win::perror(HERE);
00475 ::exit(1);
00476 }
00477 if(0== ::CloseServiceHandle(scmanager) )
00478 {
00479 Win::perror(HERE);
00480 ::exit(1);
00481 }
00482 }
00483
00484
00485 void Service::readParameters()
00486 {
00487 RegistryKey rkey(HKEY_LOCAL_MACHINE,_regSubKey);
00488 if(!rkey)
00489 {
00490 Win::perror("Can't open registry key at " HERE);
00491 ::exit(1);
00492 }
00493 _parameters=rkey.queryValueStr("Parameters");
00494 if(_parameters==NULL)
00495 {
00496 Win::perror("Can't get Parameters at " HERE);
00497 ::exit(1);
00498 }
00499 }
00500
00501
00502 void Service::writeParameters(int argc, char** argv) const
00503 {
00504 RegistryKey rkey(HKEY_LOCAL_MACHINE,_regSubKey,KEY_SET_VALUE);
00505 if(!rkey)
00506 {
00507 Win::perror("Can't open registry key at " HERE);
00508 ::exit(1);
00509 }
00510 string parameters ="";
00511 for(int i=2; i<argc; ++i)
00512 {
00513 if(!parameters.empty())
00514 parameters+=" ";
00515 parameters+=argv[i];
00516 }
00517 if(0!= rkey.setValueStr("Parameters",parameters.c_str()) )
00518 {
00519 Win::perror("Can't set registry value 'Parameters' at " HERE);
00520 ::exit(1);
00521 }
00522 }
00523
00524
00525 bool Service::setServiceStatus(
00526 DWORD currentState,
00527 DWORD win32ExitCode,
00528 DWORD serviceSpecificExitCode,
00529 DWORD checkPoint,
00530 DWORD waitHint)
00531 {
00532 SERVICE_STATUS s;
00533 s.dwServiceType =SERVICE_WIN32_OWN_PROCESS;
00534 s.dwCurrentState =currentState;
00535 s.dwServiceSpecificExitCode=serviceSpecificExitCode;
00536 s.dwCheckPoint =checkPoint;
00537 s.dwWaitHint =waitHint;
00538
00539 if(currentState==SERVICE_START_PENDING)
00540 s.dwControlsAccepted=0;
00541 else
00542 s.dwControlsAccepted=SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
00543
00544 if(serviceSpecificExitCode==0)
00545 s.dwWin32ExitCode=win32ExitCode;
00546 else
00547 s.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;
00548
00549 return (0!= ::SetServiceStatus(_serviceStatusHandle,&s) );
00550 }
00551
00552 }