/*- * Copyright 2005 Guram Dukashvili * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ //--------------------------------------------------------------------------- #include //--------------------------------------------------------------------------- namespace ksys { //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- Service::~Service() { } //--------------------------------------------------------------------------- Service::Service() #if defined(__WIN32__) || defined(__WIN64__) : serviceNameW_(utf8::String().getUNICODEString()) #else : status_(svcReady) #endif { #if defined(__WIN32__) || defined(__WIN64__) statusHandle_ = 0; #endif } //--------------------------------------------------------------------------- #if defined(__WIN32__) || defined(__WIN64__) //--------------------------------------------------------------------------- Service & Service::serviceMain(uintptr_t n,DWORD dwArgc,LPWSTR * lpszArgv) { uintptr_t i; int32_t err; try { for( i = 0; i < dwArgc; i++ ) argv().add(lpszArgv[i]); statusHandle_ = RegisterServiceCtrlHandlerW( serviceName_.getUNICODEString(), Services::handlers_[n] ); if( statusHandle_ == 0 ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } serviceStatus_.dwServiceType = serviceType_; serviceStatus_.dwCurrentState = SERVICE_START_PENDING; serviceStatus_.dwWin32ExitCode = NO_ERROR; serviceStatus_.dwServiceSpecificExitCode = ERROR_SUCCESS; serviceStatus_.dwCheckPoint = 0; if( SetServiceStatus(statusHandle_,&serviceStatus_) == 0 ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } start(); serviceStatus_.dwCurrentState = SERVICE_RUNNING; if( SetServiceStatus(statusHandle_,&serviceStatus_) == 0 ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } /* MSG msg; for(;;){ if( PeekMessage(&msg,NULL,0,0,PM_REMOVE) != 0 ){ TranslateMessage(&msg); DispatchMessage(&msg); } if( msg.message == WM_QUIT ) break; if( WaitMessage() == 0 ){ long err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } }*/ semaphore_.wait(); serviceStatus_.dwCurrentState = SERVICE_STOP_PENDING; if( SetServiceStatus(statusHandle_,&serviceStatus_) == 0 ){ err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } stop(); } catch( ExceptionSP & e ){ e->writeStdError(); serviceStatus_.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; serviceStatus_.dwServiceSpecificExitCode = e->code() >= errorOffset ? e->code() - errorOffset : e->code(); } catch( ... ){ serviceStatus_.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; serviceStatus_.dwServiceSpecificExitCode = DWORD(-1); } serviceStatus_.dwCurrentState = SERVICE_STOPPED; BOOL r = SetServiceStatus(statusHandle_,&serviceStatus_); assert( r != 0 ); if( r == 0 ) abort(); return *this; } //--------------------------------------------------------------------------- Service & Service::handler(uintptr_t /*n*/,DWORD fdwControl) { if( fdwControl == SERVICE_CONTROL_STOP ) semaphore_.post(); return *this; } //--------------------------------------------------------------------------- Service & Service::install(SC_HANDLE hSCManager) { install(); utf8::WideString serviceNameW(serviceName_.getUNICODEString()); utf8::WideString displayNameW(displayName_.getUNICODEString()); utf8::WideString binaryPathNameW((args_.strlen() > 0 ? binaryPathName_ + args_ : binaryPathName_).getUNICODEString()); utf8::WideString loadOrderGroupW(loadOrderGroup_.getUNICODEString()); utf8::WideString dependenciesW(dependencies_.getUNICODEString()); utf8::WideString serviceStartNameW(serviceStartName_.getUNICODEString()); utf8::WideString passwordW(password_.getUNICODEString()); SC_HANDLE handle = CreateServiceW( hSCManager, serviceNameW, displayNameW, SERVICE_ALL_ACCESS, serviceType_, startType_, errorControl_, binaryPathNameW, loadOrderGroup_.strlen() > 0 ? (wchar_t *) loadOrderGroupW : NULL, (serviceType_ == SERVICE_KERNEL_DRIVER || serviceType_ == SERVICE_FILE_SYSTEM_DRIVER) && (startType_ == SERVICE_BOOT_START || startType_ == SERVICE_SYSTEM_START) ? &tagId_ : NULL, dependencies_.strlen() > 0 ? (wchar_t *) dependenciesW : NULL, serviceStartName_.strlen() > 0 ? (wchar_t *) serviceStartNameW : NULL, password_.strlen() > 0 ? (wchar_t *) passwordW : NULL ); if( handle == NULL ){ int32_t err = GetLastError(); if( err == ERROR_SERVICE_EXISTS ){ SetLastError(err = ERROR_SUCCESS); handle = OpenServiceW(hSCManager,serviceNameW,SERVICE_ALL_ACCESS); if( handle == NULL || ChangeServiceConfigW(handle, serviceType_, startType_, errorControl_, binaryPathNameW, loadOrderGroup_.strlen() > 0 ? (wchar_t *) loadOrderGroupW : NULL, (serviceType_ == SERVICE_KERNEL_DRIVER || serviceType_ == SERVICE_FILE_SYSTEM_DRIVER) && (startType_ == SERVICE_BOOT_START || startType_ == SERVICE_SYSTEM_START) ? &tagId_ : NULL, dependencies_.strlen() > 0 ? (wchar_t *) dependenciesW : NULL, serviceStartName_.strlen() > 0 ? (wchar_t *) serviceStartNameW : NULL, password_.strlen() > 0 ? (wchar_t *) passwordW : NULL, displayNameW ) == 0 ) err = GetLastError(); } if( err != ERROR_SUCCESS ){ if( handle != NULL ) CloseServiceHandle(handle); newObjectV1C2(err + errorOffset,__PRETTY_FUNCTION__)->throwSP(); } } CloseServiceHandle(handle); return *this; } //--------------------------------------------------------------------------- Service & Service::uninstall(SC_HANDLE hSCManager) { uninstall(); utf8::WideString serviceNameW(serviceName_.getUNICODEString()); SC_HANDLE handle = OpenServiceW( hSCManager, serviceNameW, SERVICE_ALL_ACCESS ); if( handle == NULL ){ int32_t err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } if( DeleteService(handle) == 0 ){ int32_t err = GetLastError() + errorOffset; CloseServiceHandle(handle); newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } CloseServiceHandle(handle); return *this; } //--------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------- void Service::install() { } //--------------------------------------------------------------------------- void Service::uninstall() { } //--------------------------------------------------------------------------- void Service::start() { newObjectV1C2(ENOSYS,"service " + serviceName_ + " not implemented start")->throwSP(); } //--------------------------------------------------------------------------- void Service::stop() { newObjectV1C2(ENOSYS,"service " + serviceName_ + " not implemented stop")->throwSP(); } //--------------------------------------------------------------------------- void Service::suspend() { newObjectV1C2(ENOSYS,"service " + serviceName_ + " not support suspending")->throwSP(); } //--------------------------------------------------------------------------- void Service::resume() { newObjectV1C2(ENOSYS,"service " + serviceName_ + " not support resuming")->throwSP(); } //--------------------------------------------------------------------------- utf8::String Service::status() { #if !defined(__WIN32__) && !defined(__WIN64__) switch( status_ ){ case svcReady : return "ready for start"; case svcStarting : return "starting"; case svcStarted : return "started"; case svcSuspending : return "suspending"; case svcSuspended : return "suspended"; case svcResuming : return "resuming"; case svcResumed : return "resumed"; case svcStoping : return "stoping"; case svcStoped : return "stoped"; default :; } #endif newObjectV1C2(EINVAL,__PRETTY_FUNCTION__)->throwSP(); return ""; } //--------------------------------------------------------------------------- bool Service::active() { return status_ == svcStarted || status_ == svcResumed; } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- #if defined(__WIN32__) || defined(__WIN64__) //--------------------------------------------------------------------------- VOID (WINAPI * const Services::serviceMains_[])(DWORD,LPWSTR *) = { serviceMainTemplate<0>, serviceMainTemplate<1>, serviceMainTemplate<2>, serviceMainTemplate<3> }; VOID (WINAPI * const Services::handlers_[])(DWORD) = { handlerTemplate<0>, handlerTemplate<1>, handlerTemplate<2>, handlerTemplate<3> }; Service * Services::services_[sizeof(serviceMains_) / sizeof(serviceMains_[0])] = { NULL, NULL, NULL, NULL }; //--------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------- Services::~Services() { clear(); #if defined(__WIN32__) || defined(__WIN64__) CloseServiceHandle(handle_); #endif } //--------------------------------------------------------------------------- Services::Services(const utf8::String & #if defined(__WIN32__) || defined(__WIN64__) ) #else name) : controlName_(name) #endif { #if defined(__WIN32__) || defined(__WIN64__) handle_ = NULL; serviceStartTable_.resize(sizeof(services_) / sizeof(services_[0]) + 1); handle_ = OpenSCManagerW(NULL,NULL,SC_MANAGER_ALL_ACCESS | GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE); if( handle_ == NULL ){ int32_t err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #endif } //--------------------------------------------------------------------------- Services & Services::clear() { #if defined(__WIN32__) || defined(__WIN64__) for( intptr_t i = sizeof(services_) / sizeof(services_[0]) - 1; i >= 0; i-- ){ /* try { services_[i]->resume(); } catch( ExceptionSP & e ){ if( e->code() != ENOSYS ) throw; } services_[i]->stop();*/ deleteObject(services_[i]); services_[i] = NULL; } #else for( intptr_t i = services_.count() - 1; i >= 0; i-- ){ try { services_[i].resume(); } catch( ExceptionSP & e ){ if( e->code() != ENOSYS ) throw; } if( services_[i].active() ) services_[i].stop(); } services_.clear(); #endif return *this; } //--------------------------------------------------------------------------- Services & Services::add(Service * service) { #if defined(__WIN32__) || defined(__WIN64__) for( uintptr_t i = 0; i < sizeof(services_) / sizeof(services_[0]); i++ ) if( services_[i] == NULL ){ services_[i] = service; break; } #else services_.add(service); #endif return *this; } //--------------------------------------------------------------------------- Services & Services::install() { #if defined(__WIN32__) || defined(__WIN64__) uintptr_t i; for( i = 0; i < sizeof(services_) / sizeof(services_[0]); i++ ){ if( services_[i] == NULL ) continue; services_[i]->install(handle_); } #endif return *this; } //--------------------------------------------------------------------------- Services & Services::uninstall() { #if defined(__WIN32__) || defined(__WIN64__) uintptr_t i; for( i = 0; i < sizeof(services_) / sizeof(services_[0]); i++ ){ if( services_[i] == NULL ) continue; services_[i]->uninstall(handle_); } #endif return *this; } //--------------------------------------------------------------------------- Service & Services::serviceByName(const utf8::String & serviceName) { intptr_t i = #if defined(__WIN32__) || defined(__WIN64__) sizeof(services_) / sizeof(services_[0]); while( --i >= 0 ) if( services_[i]->serviceName_.strcasecmp(serviceName) == 0 ) return *services_[i]; #else services_.count(); while( --i >= 0 ) if( services_[i].serviceName_.strcasecmp(serviceName) == 0 ) return services_[i]; #endif newObjectV1C2(EINVAL,"Unknown service")->throwSP(); exit(ENOSYS); } //--------------------------------------------------------------------------- Services & Services::start(const utf8::String & #if !defined(__WIN32__) && !defined(__WIN64__) serviceName #endif ) { #if !defined(__WIN32__) && !defined(__WIN64__) control_ = newObjectC1(controlName_); if( control_->creator() ) newObjectV1C2(EAGAIN,"dispatcher not started")->throwSP(); int32_t err; utf8::String error; control_->swap() << SMQ_WRL << svcStart << serviceName; control_->ref() << SMQ_RDL >> err; if( err != 0 ) control_->ref() >> error; control_->ref() << SMQ_RDU << SMQ_WRU; if( err != 0 ){ #ifndef NDEBUG fprintf(stderr,"%s\n",(const char *) error.getANSIString()); #endif newObjectV1C2(err,error)->throwSP(); } #ifndef NDEBUG fprintf(stderr,"%s\n",__PRETTY_FUNCTION__); #endif #endif return *this; } //--------------------------------------------------------------------------- Services & Services::stop(const utf8::String & #if !defined(__WIN32__) && !defined(__WIN64__) serviceName #endif ) { #if !defined(__WIN32__) && !defined(__WIN64__) control_ = newObjectC1(controlName_); if( control_->creator() ) newObjectV1C2(EAGAIN,"dispatcher not started")->throwSP(); int32_t err; utf8::String error; control_->swap() << SMQ_WRL << svcStop << serviceName; control_->ref() << SMQ_RDL >> err; if( err != 0 ) control_->ref() >> error; control_->ref() << SMQ_RDU << SMQ_WRU; if( err != 0 ){ #ifndef NDEBUG fprintf(stderr,"%s\n",(const char *) error.getANSIString()); #endif newObjectV1C2(err,error)->throwSP(); } #ifndef NDEBUG fprintf(stderr,"%s\n",__PRETTY_FUNCTION__); #endif #endif return *this; } //--------------------------------------------------------------------------- Services & Services::suspend(const utf8::String & #if !defined(__WIN32__) && !defined(__WIN64__) serviceName #endif ) { #if !defined(__WIN32__) && !defined(__WIN64__) control_ = newObjectC1(controlName_); if( control_->creator() ) newObjectV1C2(EAGAIN,"dispatcher not started")->throwSP(); int32_t err; utf8::String error; control_->swap() << SMQ_WRL << svcSuspend << serviceName; control_->ref() << SMQ_RDL >> err; if( err != 0 ) control_->ref() >> error; control_->ref() << SMQ_RDU << SMQ_WRU; if( err != 0 ){ #ifndef NDEBUG fprintf(stderr,"%s\n",(const char *) error.getANSIString()); #endif newObjectV1C2(err,error)->throwSP(); } #ifndef NDEBUG fprintf(stderr,"%s\n",__PRETTY_FUNCTION__); #endif #endif return *this; } //--------------------------------------------------------------------------- Services & Services::resume(const utf8::String & #if !defined(__WIN32__) && !defined(__WIN64__) serviceName #endif ) { #if !defined(__WIN32__) && !defined(__WIN64__) control_ = newObjectC1(controlName_); if( control_->creator() ) newObjectV1C2(EAGAIN,"dispatcher not started")->throwSP(); int32_t err; utf8::String error; control_->swap() << SMQ_WRL << svcResume << serviceName; control_->ref() << SMQ_RDL >> err; if( err != 0 ) control_->ref() >> error; control_->ref() << SMQ_RDU << SMQ_WRU; if( err != 0 ){ #ifndef NDEBUG fprintf(stderr,"%s\n",(const char *) error.getANSIString()); #endif newObjectV1C2(err,error)->throwSP(); } #ifndef NDEBUG fprintf(stderr,"%s\n",__PRETTY_FUNCTION__); #endif #endif return *this; } //--------------------------------------------------------------------------- Services & Services::query(const utf8::String & #if !defined(__WIN32__) && !defined(__WIN64__) serviceName #endif ) { #if !defined(__WIN32__) && !defined(__WIN64__) control_ = newObjectC1(controlName_); if( control_->creator() ) newObjectV1C2(EAGAIN,"dispatcher not started")->throwSP(); utf8::String sn(serviceName.strcasecmp("all") == 0 ? utf8::String() : serviceName); int32_t err; utf8::String error; control_->swap() << SMQ_WRL << svcQuery << sn; control_->ref() << SMQ_RDL >> err; if( err == 0 ){ uintptr_t count; control_->ref() >> count; while( count > 0 ){ utf8::String name, status; control_->ref() >> name >> status; fprintf(stderr,"%s: %s\n", (const char *) name.getANSIString(), (const char *) status.getANSIString() ); count--; } } else { control_->ref() >> error; } control_->ref() << SMQ_RDU << SMQ_WRU; if( err != 0 ){ #ifndef NDEBUG fprintf(stderr,"%s\n",(const char *) error.getANSIString()); #endif newObjectV1C2(err,error)->throwSP(); } #ifndef NDEBUG fprintf(stderr,"%s\n",__PRETTY_FUNCTION__); #endif #endif return *this; } //--------------------------------------------------------------------------- Services & Services::stopServiceCtrlDispatcher() { #if !defined(__WIN32__) && !defined(__WIN64__) control_ = newObjectC1(controlName_); if( control_->creator() ) newObjectV1C2(EAGAIN,"dispatcher not started")->throwSP(); int32_t err; utf8::String error; control_->swap() << SMQ_WRL << svcStopDispatcher << utf8::String(); control_->ref() << SMQ_RDL >> err; if( err != 0 ) control_->ref() >> error; control_->ref() << SMQ_RDU << SMQ_WRU; if( err != 0 ){ #ifndef NDEBUG fprintf(stderr,"%s\n",(const char *) error.getANSIString()); #endif newObjectV1C2(err,error)->throwSP(); } #ifndef NDEBUG fprintf(stderr,"%s\n",__PRETTY_FUNCTION__); #endif #endif return *this; } //--------------------------------------------------------------------------- Services & Services::startServiceCtrlDispatcher( #if defined(__WIN32__) || defined(__WIN64__) bool,bool #else bool daemonize, bool startServices #endif ) { #if defined(__WIN32__) || defined(__WIN64__) uintptr_t i; for( i = 0; i < sizeof(services_) / sizeof(services_[0]); i++ ){ if( services_[i] == NULL ) break; services_[i]->serviceNameW_ = services_[i]->serviceName_.getUNICODEString(); serviceStartTable_[i].lpServiceName = services_[i]->serviceNameW_; serviceStartTable_[i].lpServiceProc = serviceMains_[i]; } serviceStartTable_[i].lpServiceName = NULL; serviceStartTable_[i].lpServiceProc = NULL; if( StartServiceCtrlDispatcherW(serviceStartTable_.ptr()) == 0 ){ int32_t err = GetLastError() + errorOffset; newObjectV1C2(err,__PRETTY_FUNCTION__)->throwSP(); } #elif HAVE_DAEMON if( daemonize ){ int r = daemon(1,1); if( r < 0 ){ int32_t err = errno; newObjectV1C2(err,__PRETTY_FUNCTION__); } if( r > 0 ) exit(EX_OK); // if parent then immediate exit } SharedMemoryQueue::unlink(controlName_); control_ = newObjectC1(controlName_); if( !control_->creator() ) newObjectV1C2(EAGAIN,__PRETTY_FUNCTION__)->throwSP(); Thread::resume(); wait(); #else #error unsupported daemonizing interface #endif return *this; } //--------------------------------------------------------------------------- #if !defined(__WIN32__) && !defined(__WIN64__) //--------------------------------------------------------------------------- void Services::threadExecute() { #ifndef NDEBUG fprintf(stderr,"services dispatcher started\n"); #endif int32_t err; utf8::String error; intptr_t i, j; for( j = 0, i = services_.count() - 1; i >= 0; i-- ){ try { services_[i].start(); j++; } catch( ExceptionSP & e ){ e->writeStdError(); } catch( ... ){ #ifndef NDEBUG fprintf(stderr,"unexpected error while initial starting services\n"); #endif } } if( j == 0 ) terminate(); while( !terminated_ ){ ServiceDispatcherCmd cmd; utf8::String name; control_->ref() << SMQ_RDL >> cmd >> name << SMQ_RDU; err = 0; try { if( cmd == svcStart ){ #ifndef NDEBUG fprintf(stderr,"starting service %s\n",(const char *) name.getANSIString()); #endif Service & service = serviceByName(name); if( service.status_ == svcReady || service.status_ == svcStoped ){ try { service.status_ = svcStarting; service.start(); } catch( ... ){ service.status_ = svcReady; throw; } service.status_ = svcStarted; } else { err = EAGAIN; error = "service is not ready or already started"; } } else if( cmd == svcStop ){ #ifndef NDEBUG fprintf(stderr,"stopping service %s\n",(const char *) name.getANSIString()); #endif Service & service = serviceByName(name); if( service.status_ == svcStarted || service.status_ == svcResumed ){ try { service.status_ = svcStoping; service.stop(); } catch( ... ){ service.status_ = svcStarted; throw; } service.status_ = svcStoped; } else { err = EAGAIN; error = "service is not started or resumed"; } } else if( cmd == svcSuspend ){ #ifndef NDEBUG fprintf(stderr,"suspending service %s\n",(const char *) name.getANSIString()); #endif Service & service = serviceByName(name); if( service.status_ == svcStarted || service.status_ == svcResumed ){ try { service.status_ = svcSuspending; service.suspend(); } catch( ... ){ service.status_ = svcStarted; throw; } service.status_ = svcSuspended; } else { err = EAGAIN; error = "service is not started or resumed"; } } else if( cmd == svcResume ){ #ifndef NDEBUG fprintf(stderr,"resuming service %s\n",(const char *) name.getANSIString()); #endif Service & service = serviceByName(name); if( service.status_ == svcSuspended ){ try { service.status_ = svcResuming; service.suspend(); } catch( ... ){ service.status_ = svcResumed; throw; } service.status_ = svcSuspended; } else { err = EAGAIN; error = "service is not started or suspended"; } } else if( cmd == svcQuery ){ if( name.strlen() > 0 ){ Service & service = serviceByName(name); control_->ref() << SMQ_WRL << err << uintptr_t(1) << name; try { if( (service.status_ == svcStarted || service.status_ == svcResumed) && !service.active() ){ service.status_ = svcStoped; } control_->ref() << service.status(); } catch( ... ){ control_->ref() << SMQ_WRU; throw; } control_->ref() << SMQ_WRU; } else { control_->ref() << SMQ_WRL << err << services_.count(); for( uintptr_t i = 0; services_.count(); i++ ){ control_->ref() << services_[i].serviceName_; try { control_->ref() << services_[i].status(); } catch( ... ){ control_->ref() << SMQ_WRU; } } control_->ref() << SMQ_WRU; } continue; } else if( cmd == svcStopDispatcher ){ #ifndef NDEBUG fprintf(stderr,"stopping services dispatcher\n"); #endif terminate(); } else { newObjectV1C2(EINVAL,"Unknown command")->throwSP(); } } catch( ExceptionSP & e ){ e->writeStdError(); err = e->code(); error = e->what(); } catch( ... ){ err = EFAULT; error = "Unknown error"; } control_->ref() << SMQ_WRL << err; if( err != 0 ) control_->ref() << error; control_->ref() << SMQ_WRU; } #ifndef NDEBUG fprintf(stderr,"services dispatcher stopped\n"); #endif } //--------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------- } // namespace ksys //---------------------------------------------------------------------------