2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 PowerDNS.COM BV
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 \brief This file contains the NTService class implementation.
29 #include "ntservice.hh"
31 #define L theL("pdns")
34 // Default constructor.
35 NTService::NTService( void )
37 m_runningAsService
= false;
40 m_serviceStatusHandle
= NULL
;
45 NTService::~NTService( void )
50 // Returns whether the program is running as a service.
51 bool NTService::isRunningAsService( void )
53 return m_runningAsService
;
57 // Registers the service.
58 bool NTService::registerService( const std::string
& description
, bool registerLog
)
60 std::stringstream str
;
66 sc
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
68 return false; // Could not open the Service Control Manager.
70 GetModuleFileName( NULL
, temp
, sizeof( temp
));
72 str
<< temp
<< " --ntservice";
76 getServiceName().c_str(),
77 getServiceName().c_str(),
79 SERVICE_WIN32_OWN_PROCESS
,
89 if(GetLastError() != ERROR_SERVICE_EXISTS
)
90 return false; // Don't we all like functions with 43 billion parameters?
92 CloseServiceHandle( sc
);
97 if ( !description
.empty())
99 str
<< "SYSTEM\\CurrentControlSet\\Services\\" << getServiceName();
101 if ( RegCreateKey( HKEY_LOCAL_MACHINE
, str
.str().c_str(), &key
) != ERROR_SUCCESS
)
104 if ( RegSetValueEx( key
, "Description", 0, REG_SZ
, reinterpret_cast< const unsigned char * >( description
.c_str()), description
.length()) != ERROR_SUCCESS
)
113 // Register event log.
118 str
<< "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\" << getServiceName();
119 if ( RegCreateKey( HKEY_LOCAL_MACHINE
, str
.str().c_str(), &pkey
) != ERROR_SUCCESS
)
122 flags
= EVENTLOG_ERROR_TYPE
| EVENTLOG_WARNING_TYPE
| EVENTLOG_INFORMATION_TYPE
;
124 if ( RegSetValueEx( pkey
, "TypesSupported", 0, REG_DWORD
, reinterpret_cast< const unsigned char * >( &flags
), sizeof( flags
)) != ERROR_SUCCESS
)
130 // For the message file this function assumes %SystemRoot%\\System32\\<servicename>msg.dll
133 char path
[ MAX_PATH
];
134 GetCurrentDirectory( sizeof( path
), path
);
136 // FIXME: This really should be: str << path << "\\" << getServiceName() << "msg.dll";
137 str
<< path
<< "\\Eventlogger.dll";
138 if ( RegSetValueEx( pkey
, "EventMessageFile", 0, REG_SZ
, reinterpret_cast< const unsigned char * >( str
.str().c_str()), str
.str().length()) != ERROR_SUCCESS
)
151 // Calls the control handler.
152 void WINAPI
NTService::s_ctrlHandler( DWORD controlCode
)
154 NTService::instance()->ctrlHandler( controlCode
);
158 // Calls the service's main function.
159 void WINAPI
NTService::s_serviceMain( DWORD argc
, LPTSTR
*argv
)
163 NTService::instance()->m_serviceStatusHandle
= RegisterServiceCtrlHandler( NTService::instance()->getServiceName().c_str(), s_ctrlHandler
);
164 if ( NTService::instance()->m_serviceStatusHandle
== 0 )
166 // Could not register service ctrl handler.
170 NTService::instance()->setStatus( SERVICE_START_PENDING
);
172 if ( !NTService::instance()->init())
174 NTService::instance()->setStatus( SERVICE_STOPPED
, -1 );
178 NTService::instance()->setStatus( SERVICE_RUNNING
);
181 NTService::instance()->main( argc
, argv
);
183 NTService::instance()->setStatus( SERVICE_STOP_PENDING
);
186 NTService::instance()->shutdown();
188 NTService::instance()->setStatus( SERVICE_STOPPED
);
192 // Sets the service's status.
193 void NTService::setStatus( DWORD status
, DWORD error
)
197 if ( !m_serviceStatusHandle
)
200 stat
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
201 stat
.dwCurrentState
= status
;
202 stat
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
;
203 stat
.dwWin32ExitCode
= ( error
? ERROR_SERVICE_SPECIFIC_ERROR
: NO_ERROR
);
204 stat
.dwServiceSpecificExitCode
= error
;
205 stat
.dwCheckPoint
= 0;
208 SetServiceStatus( m_serviceStatusHandle
, &stat
);
212 // Starts the service.
213 int NTService::start( int argc
, char *argv
[], bool asService
)
218 strncpy( name
, getServiceName().c_str(), sizeof( name
));
220 SERVICE_TABLE_ENTRY entries
[] =
222 { name
, s_serviceMain
},
229 m_runningAsService
= true;
231 if ( StartServiceCtrlDispatcher( entries
))
232 return 0; // Success!
234 // StartServiceCtrlDispatcher() failed, check if we should run as a normal
236 if ( GetLastError() != ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
)
241 DLOG( L
<< "Running as a normal (console) program." << endl
);
243 // Run as normal (console) program.
244 m_runningAsService
= false;
247 return -1; // Could not initialize.
250 res
= main( argc
, argv
);
258 // Stops the service.
259 bool NTService::stop( void )
261 if ( !isRunningAsService())
264 setStatus( SERVICE_STOPPED
, 0 );
270 // Unregister service.
271 bool NTService::unregisterService( void )
276 sc
= OpenSCManager( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
280 svc
= OpenService( sc
, getServiceName().c_str(), DELETE
);
281 if ( GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST
)
285 CloseServiceHandle( sc
);
289 DeleteService( svc
);
290 CloseServiceHandle( svc
);
291 CloseServiceHandle( sc
);
294 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application", 0, KEY_WRITE
, &key
) != ERROR_SUCCESS
)
297 RegDeleteKey( key
, getServiceName().c_str());