source: nscp/NSClient++.cpp @ 452fd41

0.4.00.4.10.4.2stable
Last change on this file since 452fd41 was 452fd41, checked in by Michael Medin <michael@…>, 8 years ago
  • Changed the Thread class a bit (mutex -> signal, and CreatThread? does not return the instance)
  • Moved settings "keys" fro NRPE to config.h
  • Changed build options (added Distribution) which builds a zip file under ./dist (requires 7z installed)
  • Minor tweaks to error/debug logging and small fixes "here and there"
  • Property mode set to 100644
File size: 12.7 KB
Line 
1//////////////////////////////////////////////////////////////////////////
2// NSClient++ Base Service
3//
4// Copyright (c) 2004 MySolutions NORDIC (http://www.medin.name)
5//
6// Date: 2004-03-13
7// Author: Michael Medin (michael@medin.name)
8//
9// Part of this file is based on work by Bruno Vais (bvais@usa.net)
10//
11// This software is provided "AS IS", without a warranty of any kind.
12// You are free to use/modify this code but leave this header intact.
13//
14//////////////////////////////////////////////////////////////////////////
15#include "stdafx.h"
16#include <winsvc.h>
17#include "NSClient++.h"
18#include "Settings.h"
19#include <charEx.h>
20#include <Socket.h>
21
22NSClient mainClient;    // Global core instance.
23bool g_bConsoleLog = false;
24//////////////////////////////////////////////////////////////////////////
25// Startup code
26
27/**
28 * Application startup point
29 *
30 * @param argc Argument count
31 * @param argv[] Argument array
32 * @param envp[] Environment array
33 * @return exit status
34 */
35int main(int argc, TCHAR* argv[], TCHAR* envp[])
36{
37        int nRetCode = 0;
38
39        if ( (argc > 1) && ((*argv[1] == '-') || (*argv[1] == '/')) ) {
40                if ( _stricmp( "install", argv[1]+1 ) == 0 ) {
41                        g_bConsoleLog = true;
42                        try {
43                                serviceControll::Install(SZSERVICENAME, SZSERVICEDISPLAYNAME, SZDEPENDENCIES);
44                        } catch (const serviceControll::SCException& e) {
45                                LOG_MESSAGE_STD("Service installation failed: " + e.error_);
46                                return -1;
47                        }
48                        LOG_MESSAGE("Service installed!");
49                } else if ( _stricmp( "uninstall", argv[1]+1 ) == 0 ) {
50                        g_bConsoleLog = true;
51                        try {
52                                serviceControll::Uninstall(SZSERVICENAME);
53                        } catch (const serviceControll::SCException& e) {
54                                LOG_MESSAGE_STD("Service deinstallation failed; " + e.error_);
55                                return -1;
56                        }
57                } else if ( _stricmp( "start", argv[1]+1 ) == 0 ) {
58                        g_bConsoleLog = true;
59                        serviceControll::Start(SZSERVICENAME);
60                } else if ( _stricmp( "stop", argv[1]+1 ) == 0 ) {
61                        g_bConsoleLog = true;
62                        serviceControll::Stop(SZSERVICENAME);
63                } else if ( _stricmp( "about", argv[1]+1 ) == 0 ) {
64                        g_bConsoleLog = true;
65                        LOG_MESSAGE(SZAPPNAME " (C) Michael Medin");
66                        LOG_MESSAGE("Version " SZVERSION);
67                } else if ( _stricmp( "version", argv[1]+1 ) == 0 ) {
68                        g_bConsoleLog = true;
69                        LOG_MESSAGE(SZAPPNAME " Version: " SZVERSION);
70                } else if ( _stricmp( "test", argv[1]+1 ) == 0 ) {
71#ifdef _DEBUG
72                        strEx::run_test_getToken();
73                        strEx::run_test_replace();
74                        charEx::run_test_getToken();
75                        arrayBuffer::run_testArrayBuffer();
76#endif
77
78                        g_bConsoleLog = true;
79                        mainClient.InitiateService();
80                        LOG_MESSAGE("Enter command to inject or exit to terminate...");
81                        std::string s = "";
82                        std::cin >> s;
83                        while (s != "exit") {
84//                              mainClient.inject(s);
85                                std::cin >> s;
86                        }
87                        mainClient.TerminateService();
88                        LOG_MESSAGE("DONE!");
89
90                        return 0;
91                } else {
92                        LOG_MESSAGE("Usage: -version, -about, -install, -uninstall, -start, -stop");
93                }
94                return nRetCode;
95        }
96        mainClient.StartServiceCtrlDispatcher();
97        return nRetCode;
98}
99
100//////////////////////////////////////////////////////////////////////////
101// Service functions
102
103/**
104 * Service control handler startup point.
105 * When the program is started as a service this will be the entry point.
106 */
107void NSClientT::InitiateService(void) {
108        Settings::getInstance()->setFile(getBasePath() + "NSC.ini");
109
110        try {
111                simpleSocket::Socket::WSAStartup();
112        } catch (simpleSocket::SocketException e) {
113                LOG_ERROR_STD("Uncaught exception: " + e.getMessage());
114        }
115
116        SettingsT::sectionList list = Settings::getInstance()->getSection("modules");
117        for (SettingsT::sectionList::iterator it = list.begin(); it != list.end(); it++) {
118                try {
119                        LOG_DEBUG_STD("Loading: " + getBasePath() + "modules\\" + (*it));
120                        loadPlugin(getBasePath() + "modules\\" + (*it));
121                } catch(const NSPluginException& e) {
122                        LOG_ERROR_STD("Exception raised: " + e.error_ + " in module: " + e.file_);
123                }
124        }
125}
126/**
127 * Service control handler termination point.
128 * When the program is stopped as a service this will be the "exit point".
129 */
130void NSClientT::TerminateService(void) {
131        try {
132                mainClient.unloadPlugins();
133                LOG_DEBUG("Plugins unloaded...");
134        } catch(NSPluginException *e) {
135                std::cout << "Exception raised: " << e->error_ << " in module: " << e->file_ << std::endl;;
136        }
137        try {
138                simpleSocket::Socket::WSACleanup();
139        } catch (simpleSocket::SocketException e) {
140                LOG_ERROR_STD("Uncaught exception: " + e.getMessage());
141        }
142        Settings::destroyInstance();
143}
144
145/**
146 * Forward this to the main service dispatcher helper class
147 * @param dwArgc
148 * @param *lpszArgv
149 */
150void WINAPI NSClientT::service_main_dispatch(DWORD dwArgc, LPTSTR *lpszArgv) {
151        mainClient.service_main(dwArgc, lpszArgv);
152}
153/**
154 * Forward this to the main service dispatcher helper class
155 * @param dwCtrlCode
156 */
157void WINAPI NSClientT::service_ctrl_dispatch(DWORD dwCtrlCode) {
158        mainClient.service_ctrl(dwCtrlCode);
159}
160
161//////////////////////////////////////////////////////////////////////////
162// Member functions
163
164
165/**
166 * Load a list of plug-ins
167 * @param plugins A list with plug-ins (DLL files) to load
168 */
169void NSClientT::loadPlugins(const std::list<std::string> plugins) {
170        MutexLock lock(pluginMutex);
171        if (!lock.hasMutex()) {
172                LOG_ERROR("FATAL ERROR: Could not get mutex.");
173                return;
174        }
175        std::list<std::string>::const_iterator it;
176        for (it = plugins.begin(); it != plugins.end(); ++it) {
177                loadPlugin(*it);
178        }
179}
180/**
181 * Unload all plug-ins (in reversed order)
182 */
183void NSClientT::unloadPlugins() {
184        MutexLock lock(pluginMutex,20000);
185        if (!lock.hasMutex()) {
186                LOG_ERROR("FATAL ERROR: Could not get mutex.");
187                return;
188        }
189        pluginList::reverse_iterator it;
190        for (it = plugins_.rbegin(); it != plugins_.rend(); ++it) {
191                LOG_DEBUG_STD("Unloading plugin: " + (*it)->getName() + "...");
192                (*it)->unload();
193        }
194        {
195                MutexLock lock2(messageMutex,20000);
196                if (!lock2.hasMutex()) {
197                        LOG_ERROR("FATAL ERROR: Could not get mutex (we will now crash BTW).");
198                } else {
199                        messageHandlers_.clear();
200                }
201        }
202        commandHandlers_.clear();
203        for (it = plugins_.rbegin(); it != plugins_.rend(); ++it) {
204                delete (*it);
205        }
206        plugins_.clear();
207}
208/**
209 * Load a single plug-in using a DLL filename
210 * @param file The DLL file
211 */
212void NSClientT::loadPlugin(const std::string file) {
213        addPlugin(new NSCPlugin(file));
214}
215/**
216 * Load and add a plugin to various internal structures
217 * @param *plugin The plug-ininstance to load. The pointer is managed by the
218 */
219void NSClientT::addPlugin(plugin_type plugin) {
220        MutexLock lock(pluginMutex);
221        if (!lock.hasMutex()) {
222                LOG_ERROR("FATAL ERROR: Could not get mutex.");
223                return;
224        }
225        plugin->load();
226        LOG_DEBUG_STD("Loading: " + plugin->getName());
227        // @todo Catch here and unload if we fail perhaps ?
228        plugins_.push_back(plugin);
229        if (plugin->hasCommandHandler())
230                commandHandlers_.push_back(plugin);
231        if (plugin->hasMessageHandler())
232                messageHandlers_.push_back(plugin);
233}
234/**
235 * Inject a command into the plug-in stack.
236 *
237 * @param buffer A command string to inject. This should be a unparsed command string such as command&arg1&arg2&arg...
238 * @return The result, empty string if no result
239 */
240NSCAPI::nagiosReturn NSClientT::injectRAW(const char* command, const unsigned int argLen, char **argument, char *returnMessageBuffer, unsigned int returnMessageBufferLen, char *returnPerfBuffer, unsigned int returnPerfBufferLen) {
241        MutexLock lock(pluginMutex);
242
243        pluginList::const_iterator plit;
244        for (plit = commandHandlers_.begin(); plit != commandHandlers_.end(); ++plit) {
245                try {
246                        NSCAPI::nagiosReturn c = (*plit)->handleCommand(command, argLen, argument, returnMessageBuffer, returnMessageBufferLen, returnPerfBuffer, returnPerfBufferLen);
247                        switch (c) {
248                                case NSCAPI::returnInvalidBufferLen:
249                                        LOG_ERROR("Return buffer to small to handle this command.");
250                                        return c;
251                                case NSCAPI::returnIgnored:
252                                        LOG_DEBUG("A module ignored this message");
253                                        break;
254                                case NSCAPI::returnOK:
255                                case NSCAPI::returnWARN:
256                                case NSCAPI::returnCRIT:
257                                case NSCAPI::returnUNKNOWN:
258                                        LOG_DEBUG_STD("Injected Result: " +(std::string) returnMessageBuffer);
259                                        LOG_DEBUG_STD("Injected Performance Result: " +(std::string) returnPerfBuffer);
260                                        return c;
261                                default:
262                                        LOG_ERROR_STD("Unknown error from handleCommand: " + strEx::itos(c));
263                                        return c;
264                        }
265                } catch(const NSPluginException& e) {
266                        LOG_ERROR_STD("Exception raised: " + e.error_ + " in module: " + e.file_);
267                        return NSCAPI::returnCRIT;
268                }
269        }
270        LOG_MESSAGE_STD("No handler for command: " + command);
271        return NSCAPI::returnIgnored;
272}
273/**
274 * Report a message to all logging enabled modules.
275 *
276 * @param msgType Message type
277 * @param file Filename generally __FILE__
278 * @param line  Line number, generally __LINE__
279 * @param message The message as a human readable string.
280 */
281void NSClientT::reportMessage(int msgType, const char* file, const int line, std::string message) {
282        MutexLock lock(messageMutex);
283        if (!lock.hasMutex()) {
284                std::cout << "Message was lost as the core was locked..." << std::endl;
285                std::cout << message << std::endl;
286                return;
287        }
288        if (g_bConsoleLog) {
289                std::cout << NSCHelper::translateMessageType(msgType) << " " << file << "(" << line << ") " << message << std::endl;
290        }
291        if (msgType == NSCAPI::debug) {
292                typedef enum status {unknown, debug, nodebug };
293                static status d = unknown;
294                if (d == unknown) {
295                        if (Settings::getInstance()->getInt("log", "debug", 0) == 1)
296                                d = debug;
297                        else
298                                d = nodebug;
299                }
300                if (d == nodebug)
301                        return;
302        }
303        pluginList::const_iterator plit;
304        for (plit = messageHandlers_.begin(); plit != messageHandlers_.end(); ++plit) {
305                try {
306                        (*plit)->handleMessage(msgType, file, line, message.c_str());
307                } catch(const NSPluginException& e) {
308                        // Here we are pretty much fucked! (as logging this might cause a loop :)
309                        std::cout << "Caught: " << e.error_ << " when trying to log a message..." << std::endl;
310                        std::cout << "This is *really really* bad, now the world is about to end..." << std::endl;
311                }
312        }
313}
314std::string NSClientT::getBasePath(void) {
315        MutexLock lock(pluginMutex);
316        if (!lock.hasMutex()) {
317                LOG_ERROR("FATAL ERROR: Could not get mutex.");
318                return "FATAL ERROR";
319        }
320        if (!basePath.empty())
321                return basePath;
322        char* buffer = new char[1024];
323        GetModuleFileName(NULL, buffer, 1023);
324        std::string path = buffer;
325        std::string::size_type pos = path.rfind('\\');
326        basePath = path.substr(0, pos) + "\\";
327        delete [] buffer;
328        Settings::getInstance()->setFile(basePath + "NSC.ini");
329        return basePath;
330}
331
332
333NSCAPI::errorReturn NSAPIGetSettingsString(const char* section, const char* key, const char* defaultValue, char* buffer, unsigned int bufLen) {
334        return NSCHelper::wrapReturnString(buffer, bufLen, Settings::getInstance()->getString(section, key, defaultValue), NSCAPI::isSuccess);
335}
336int NSAPIGetSettingsInt(const char* section, const char* key, int defaultValue) {
337        return Settings::getInstance()->getInt(section, key, defaultValue);
338}
339NSCAPI::errorReturn NSAPIGetBasePath(char*buffer, unsigned int bufLen) {
340        return NSCHelper::wrapReturnString(buffer, bufLen, mainClient.getBasePath(), NSCAPI::isSuccess);
341}
342NSCAPI::errorReturn NSAPIGetApplicationName(char*buffer, unsigned int bufLen) {
343        return NSCHelper::wrapReturnString(buffer, bufLen, SZAPPNAME, NSCAPI::isSuccess);
344}
345NSCAPI::errorReturn NSAPIGetApplicationVersionStr(char*buffer, unsigned int bufLen) {
346        return NSCHelper::wrapReturnString(buffer, bufLen, SZVERSION, NSCAPI::isSuccess);
347}
348void NSAPIMessage(int msgType, const char* file, const int line, const char* message) {
349        mainClient.reportMessage(msgType, file, line, message);
350}
351void NSAPIStopServer(void) {
352        serviceControll::Stop(SZSERVICENAME);
353}
354NSCAPI::nagiosReturn NSAPIInject(const char* command, const unsigned int argLen, char **argument, char *returnMessageBuffer, unsigned int returnMessageBufferLen, char *returnPerfBuffer, unsigned int returnPerfBufferLen) {
355        return mainClient.injectRAW(command, argLen, argument, returnMessageBuffer, returnMessageBufferLen, returnPerfBuffer, returnPerfBufferLen);
356}
357NSCAPI::errorReturn NSAPIGetSettingsSection(const char* section, char*** aBuffer, unsigned int * bufLen) {
358        unsigned int len = 0;
359        *aBuffer = arrayBuffer::list2arrayBuffer(Settings::getInstance()->getSection(section), len);
360        *bufLen = len;
361        return NSCAPI::isSuccess;
362}
363
364
365LPVOID NSAPILoader(char*buffer) {
366        if (stricmp(buffer, "NSAPIGetApplicationName") == 0)
367                return &NSAPIGetApplicationName;
368        if (stricmp(buffer, "NSAPIGetApplicationVersionStr") == 0)
369                return &NSAPIGetApplicationVersionStr;
370        if (stricmp(buffer, "NSAPIGetSettingsSection") == 0)
371                return &NSAPIGetSettingsSection;
372        if (stricmp(buffer, "NSAPIGetSettingsString") == 0)
373                return &NSAPIGetSettingsString;
374        if (stricmp(buffer, "NSAPIGetSettingsInt") == 0)
375                return &NSAPIGetSettingsInt;
376        if (stricmp(buffer, "NSAPIMessage") == 0)
377                return &NSAPIMessage;
378        if (stricmp(buffer, "NSAPIStopServer") == 0)
379                return &NSAPIStopServer;
380        if (stricmp(buffer, "NSAPIInject") == 0)
381                return &NSAPIInject;
382        if (stricmp(buffer, "NSAPIGetBasePath") == 0)
383                return &NSAPIGetBasePath;
384        return NULL;
385}
Note: See TracBrowser for help on using the repository browser.