agent restart issues restart command to all connected external subagents
[public/netxms.git] / src / agent / core / extagent.cpp
CommitLineData
204ace22
VK
1/*
2** NetXMS multiplatform core agent
eb17778f 3** Copyright (C) 2003-2017 Victor Kirhenshtein
204ace22
VK
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
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.
14**
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** File: extagent.cpp
20**
21**/
22
23#include "nxagentd.h"
24
204ace22 25
639088d4
VK
26/**
27 *Static data
28 */
204ace22
VK
29static ObjectArray<ExternalSubagent> s_subagents;
30
0df58041
VK
31/**
32 * Constructor
33 */
e464b7dc 34ExternalSubagent::ExternalSubagent(const TCHAR *name, const TCHAR *user)
204ace22
VK
35{
36 nx_strncpy(m_name, name, MAX_SUBAGENT_NAME);
e464b7dc 37 nx_strncpy(m_user, user, MAX_ESA_USER_NAME);
204ace22 38 m_connected = false;
84d1bd22 39 m_pipe = INVALID_PIPE_HANDLE;
0df58041
VK
40 m_msgQueue = new MsgWaitQueue();
41 m_requestId = 1;
42 m_mutexPipeWrite = MutexCreate();
204ace22
VK
43}
44
0df58041
VK
45/**
46 * Destructor
47 */
204ace22
VK
48ExternalSubagent::~ExternalSubagent()
49{
0df58041
VK
50 delete m_msgQueue;
51 MutexDestroy(m_mutexPipeWrite);
204ace22
VK
52}
53
0df58041
VK
54/*
55 * Send message to external subagent
56 */
b368969c 57bool ExternalSubagent::sendMessage(NXCPMessage *msg)
0df58041
VK
58{
59 TCHAR buffer[256];
b368969c 60 AgentWriteDebugLog(6, _T("ExternalSubagent::sendMessage(%s): sending message %s"), m_name, NXCPMessageCodeName(msg->getCode(), buffer));
204ace22 61
b368969c 62 NXCP_MESSAGE *rawMsg = msg->createMessage();
c17f6cbc 63 MutexLock(m_mutexPipeWrite);
e41fc6fc 64 bool success = SendMessageToPipe(m_pipe, rawMsg);
0df58041
VK
65 MutexUnlock(m_mutexPipeWrite);
66 free(rawMsg);
639088d4 67 return success;
0df58041 68}
204ace22 69
0df58041
VK
70/**
71 * Wait for specific message to arrive
72 */
b368969c 73NXCPMessage *ExternalSubagent::waitForMessage(WORD code, UINT32 id)
0df58041 74{
c17f6cbc 75 return m_msgQueue->waitForMessage(code, id, 5000); // 5 sec timeout
0df58041
VK
76}
77
0df58041
VK
78/**
79 * Main connection thread
80 */
84d1bd22 81void ExternalSubagent::connect(HPIPE hPipe)
204ace22
VK
82{
83 TCHAR buffer[256];
1a7c8d1e 84 UINT32 i;
204ace22
VK
85
86 m_pipe = hPipe;
87 m_connected = true;
204ace22 88 AgentWriteDebugLog(2, _T("ExternalSubagent(%s): connection established"), m_name);
6be0a20b 89 PipeMessageReceiver receiver(hPipe, 8192, 1048576); // 8K initial, 1M max
204ace22
VK
90 while(true)
91 {
6be0a20b 92 MessageReceiverResult result;
b368969c 93 NXCPMessage *msg = receiver.readMessage(INFINITE, &result);
204ace22 94 if (msg == NULL)
6be0a20b 95 {
b368969c 96 AgentWriteDebugLog(6, _T("ExternalSubagent(%s): receiver failure (%s)"), m_name, AbstractMessageReceiver::resultToText(result));
204ace22 97 break;
6be0a20b 98 }
b368969c
VK
99 AgentWriteDebugLog(6, _T("ExternalSubagent(%s): received message %s"), m_name, NXCPMessageCodeName(msg->getCode(), buffer));
100 switch(msg->getCode())
0137b9f7
VK
101 {
102 case CMD_PUSH_DCI_DATA:
103 MutexLock(g_hSessionListAccess);
1a7c8d1e 104 for(i = 0; i < g_dwMaxSessions; i++)
0137b9f7
VK
105 if (g_pSessionList[i] != NULL)
106 if (g_pSessionList[i]->canAcceptTraps())
107 {
108 g_pSessionList[i]->sendMessage(msg);
109 }
110 MutexUnlock(g_hSessionListAccess);
111 delete msg;
112 break;
113 case CMD_TRAP:
114 ForwardTrap(msg);
115 delete msg;
116 break;
117 default:
118 m_msgQueue->put(msg);
119 break;
120 }
204ace22
VK
121 }
122
123 AgentWriteDebugLog(2, _T("ExternalSubagent(%s): connection closed"), m_name);
124 m_connected = false;
c17f6cbc 125 m_msgQueue->clear();
204ace22
VK
126}
127
f918b160
VK
128/**
129 * Send shutdown command
130 */
131void ExternalSubagent::shutdown()
132{
eb17778f 133 NXCPMessage msg(CMD_SHUTDOWN, m_requestId++);
f918b160
VK
134 sendMessage(&msg);
135}
136
eb17778f
VK
137/**
138 * Send restart command
139 */
140void ExternalSubagent::restart()
141{
142 NXCPMessage msg(CMD_RESTART, m_requestId++);
143 sendMessage(&msg);
144}
145
0df58041
VK
146/**
147 * Get list of supported parameters
148 */
967893bb 149NETXMS_SUBAGENT_PARAM *ExternalSubagent::getSupportedParameters(UINT32 *count)
0df58041 150{
b368969c 151 NXCPMessage msg;
0df58041
VK
152 NETXMS_SUBAGENT_PARAM *result = NULL;
153
b368969c
VK
154 msg.setCode(CMD_GET_PARAMETER_LIST);
155 msg.setId(m_requestId++);
639088d4 156 if (sendMessage(&msg))
0df58041 157 {
b368969c 158 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, msg.getId());
639088d4 159 if (response != NULL)
0df58041 160 {
b368969c 161 if (response->getFieldAsUInt32(VID_RCC) == ERR_SUCCESS)
0df58041 162 {
b368969c 163 *count = response->getFieldAsUInt32(VID_NUM_PARAMETERS);
639088d4 164 result = (NETXMS_SUBAGENT_PARAM *)malloc(*count * sizeof(NETXMS_SUBAGENT_PARAM));
967893bb
VK
165 UINT32 varId = VID_PARAM_LIST_BASE;
166 for(UINT32 i = 0; i < *count; i++)
639088d4 167 {
b368969c
VK
168 response->getFieldAsString(varId++, result[i].name, MAX_PARAM_NAME);
169 response->getFieldAsString(varId++, result[i].description, MAX_DB_STRING);
170 result[i].dataType = (int)response->getFieldAsUInt16(varId++);
639088d4 171 }
0df58041 172 }
639088d4 173 delete response;
0df58041 174 }
0df58041
VK
175 }
176 return result;
177}
204ace22 178
0f506caa
VK
179/**
180 * Get list of supported lists
181 */
967893bb 182NETXMS_SUBAGENT_LIST *ExternalSubagent::getSupportedLists(UINT32 *count)
0f506caa 183{
b368969c 184 NXCPMessage msg;
0f506caa
VK
185 NETXMS_SUBAGENT_LIST *result = NULL;
186
b368969c
VK
187 msg.setCode(CMD_GET_ENUM_LIST);
188 msg.setId(m_requestId++);
0f506caa
VK
189 if (sendMessage(&msg))
190 {
b368969c 191 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, msg.getId());
0f506caa
VK
192 if (response != NULL)
193 {
b368969c 194 if (response->getFieldAsUInt32(VID_RCC) == ERR_SUCCESS)
0f506caa 195 {
b368969c 196 *count = response->getFieldAsUInt32(VID_NUM_ENUMS);
0f506caa 197 result = (NETXMS_SUBAGENT_LIST *)malloc(*count * sizeof(NETXMS_SUBAGENT_LIST));
967893bb
VK
198 UINT32 varId = VID_ENUM_LIST_BASE;
199 for(UINT32 i = 0; i < *count; i++)
0f506caa 200 {
b368969c 201 response->getFieldAsString(varId++, result[i].name, MAX_PARAM_NAME);
0f506caa
VK
202 }
203 }
204 delete response;
205 }
206 }
207 return result;
208}
209
210/**
211 * Get list of supported tables
212 */
967893bb 213NETXMS_SUBAGENT_TABLE *ExternalSubagent::getSupportedTables(UINT32 *count)
0f506caa 214{
b368969c 215 NXCPMessage msg;
0f506caa
VK
216 NETXMS_SUBAGENT_TABLE *result = NULL;
217
b368969c
VK
218 msg.setCode(CMD_GET_TABLE_LIST);
219 msg.setId(m_requestId++);
0f506caa
VK
220 if (sendMessage(&msg))
221 {
b368969c 222 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, msg.getId());
0f506caa
VK
223 if (response != NULL)
224 {
b368969c 225 if (response->getFieldAsUInt32(VID_RCC) == ERR_SUCCESS)
0f506caa 226 {
b368969c 227 *count = response->getFieldAsUInt32(VID_NUM_TABLES);
0f506caa 228 result = (NETXMS_SUBAGENT_TABLE *)malloc(*count * sizeof(NETXMS_SUBAGENT_TABLE));
967893bb
VK
229 UINT32 varId = VID_TABLE_LIST_BASE;
230 for(UINT32 i = 0; i < *count; i++)
0f506caa 231 {
b368969c
VK
232 response->getFieldAsString(varId++, result[i].name, MAX_PARAM_NAME);
233 response->getFieldAsString(varId++, result[i].instanceColumns, MAX_COLUMN_NAME * MAX_INSTANCE_COLUMNS);
234 response->getFieldAsString(varId++, result[i].description, MAX_DB_STRING);
0f506caa
VK
235 }
236 }
237 delete response;
238 }
239 }
240 return result;
241}
242
0df58041
VK
243/**
244 * List supported parameters
245 */
b368969c 246void ExternalSubagent::listParameters(NXCPMessage *msg, UINT32 *baseId, UINT32 *count)
0df58041 247{
967893bb 248 UINT32 paramCount = 0;
0df58041
VK
249 NETXMS_SUBAGENT_PARAM *list = getSupportedParameters(&paramCount);
250 if (list != NULL)
251 {
967893bb 252 UINT32 id = *baseId;
0df58041 253
967893bb 254 for(UINT32 i = 0; i < paramCount; i++)
0df58041 255 {
b368969c
VK
256 msg->setField(id++, list[i].name);
257 msg->setField(id++, list[i].description);
258 msg->setField(id++, (WORD)list[i].dataType);
0df58041
VK
259 }
260 *baseId = id;
261 *count += paramCount;
262 free(list);
263 }
264}
265
266/**
267 * List supported parameters
268 */
269void ExternalSubagent::listParameters(StringList *list)
270{
967893bb 271 UINT32 paramCount = 0;
0df58041
VK
272 NETXMS_SUBAGENT_PARAM *plist = getSupportedParameters(&paramCount);
273 if (plist != NULL)
274 {
967893bb 275 for(UINT32 i = 0; i < paramCount; i++)
0df58041
VK
276 list->add(plist[i].name);
277 free(plist);
278 }
279}
280
0f506caa
VK
281/**
282 * List supported lists
283 */
b368969c 284void ExternalSubagent::listLists(NXCPMessage *msg, UINT32 *baseId, UINT32 *count)
0f506caa 285{
967893bb 286 UINT32 paramCount = 0;
0f506caa
VK
287 NETXMS_SUBAGENT_LIST *list = getSupportedLists(&paramCount);
288 if (list != NULL)
289 {
967893bb 290 UINT32 id = *baseId;
0f506caa 291
967893bb 292 for(UINT32 i = 0; i < paramCount; i++)
0f506caa 293 {
b368969c 294 msg->setField(id++, list[i].name);
0f506caa
VK
295 }
296 *baseId = id;
297 *count += paramCount;
298 free(list);
299 }
300}
301
302/**
303 * List supported lists
304 */
305void ExternalSubagent::listLists(StringList *list)
306{
967893bb 307 UINT32 paramCount = 0;
0f506caa
VK
308 NETXMS_SUBAGENT_LIST *plist = getSupportedLists(&paramCount);
309 if (plist != NULL)
310 {
967893bb 311 for(UINT32 i = 0; i < paramCount; i++)
0f506caa
VK
312 list->add(plist[i].name);
313 free(plist);
314 }
315}
316
317/**
318 * List supported tables
319 */
b368969c 320void ExternalSubagent::listTables(NXCPMessage *msg, UINT32 *baseId, UINT32 *count)
0f506caa 321{
967893bb 322 UINT32 paramCount = 0;
0f506caa
VK
323 NETXMS_SUBAGENT_TABLE *list = getSupportedTables(&paramCount);
324 if (list != NULL)
325 {
967893bb 326 UINT32 id = *baseId;
0f506caa 327
967893bb 328 for(UINT32 i = 0; i < paramCount; i++)
0f506caa 329 {
b368969c
VK
330 msg->setField(id++, list[i].name);
331 msg->setField(id++, list[i].instanceColumns);
332 msg->setField(id++, list[i].description);
0f506caa
VK
333 }
334 *baseId = id;
335 *count += paramCount;
336 free(list);
337 }
338}
339
340/**
341 * List supported tables
342 */
343void ExternalSubagent::listTables(StringList *list)
344{
967893bb 345 UINT32 paramCount = 0;
0f506caa
VK
346 NETXMS_SUBAGENT_TABLE *plist = getSupportedTables(&paramCount);
347 if (plist != NULL)
348 {
967893bb 349 for(UINT32 i = 0; i < paramCount; i++)
0f506caa
VK
350 list->add(plist[i].name);
351 free(plist);
352 }
353}
354
0df58041
VK
355/**
356 * Get parameter value from external subagent
357 */
967893bb 358UINT32 ExternalSubagent::getParameter(const TCHAR *name, TCHAR *buffer)
0df58041 359{
b368969c 360 NXCPMessage msg;
967893bb 361 UINT32 rcc;
0df58041 362
b368969c
VK
363 msg.setCode(CMD_GET_PARAMETER);
364 msg.setId(m_requestId++);
365 msg.setField(VID_PARAMETER, name);
639088d4 366 if (sendMessage(&msg))
0df58041 367 {
b368969c 368 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, msg.getId());
639088d4
VK
369 if (response != NULL)
370 {
b368969c 371 rcc = response->getFieldAsUInt32(VID_RCC);
639088d4 372 if (rcc == ERR_SUCCESS)
b368969c 373 response->getFieldAsString(VID_VALUE, buffer, MAX_RESULT_LENGTH);
639088d4
VK
374 delete response;
375 }
376 else
377 {
378 rcc = ERR_INTERNAL_ERROR;
379 }
0df58041
VK
380 }
381 else
382 {
639088d4 383 rcc = ERR_CONNECTION_BROKEN;
0df58041
VK
384 }
385 return rcc;
386}
204ace22 387
0f506caa
VK
388/**
389 * Get table value from external subagent
390 */
967893bb 391UINT32 ExternalSubagent::getTable(const TCHAR *name, Table *value)
0f506caa 392{
b368969c 393 NXCPMessage msg;
967893bb 394 UINT32 rcc;
0f506caa 395
b368969c
VK
396 msg.setCode(CMD_GET_TABLE);
397 msg.setId(m_requestId++);
398 msg.setField(VID_PARAMETER, name);
0f506caa
VK
399 if (sendMessage(&msg))
400 {
b368969c 401 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, msg.getId());
0f506caa
VK
402 if (response != NULL)
403 {
b368969c 404 rcc = response->getFieldAsUInt32(VID_RCC);
0f506caa
VK
405 if (rcc == ERR_SUCCESS)
406 value->updateFromMessage(response);
407 delete response;
408 }
409 else
410 {
411 rcc = ERR_INTERNAL_ERROR;
412 }
413 }
414 else
415 {
416 rcc = ERR_CONNECTION_BROKEN;
417 }
418 return rcc;
419}
420
421/**
422 * Get list value from external subagent
423 */
967893bb 424UINT32 ExternalSubagent::getList(const TCHAR *name, StringList *value)
0f506caa 425{
b368969c 426 NXCPMessage msg;
967893bb 427 UINT32 rcc;
0f506caa 428
b368969c
VK
429 msg.setCode(CMD_GET_LIST);
430 msg.setId(m_requestId++);
431 msg.setField(VID_PARAMETER, name);
0f506caa
VK
432 if (sendMessage(&msg))
433 {
b368969c 434 NXCPMessage *response = waitForMessage(CMD_REQUEST_COMPLETED, msg.getId());
0f506caa
VK
435 if (response != NULL)
436 {
b368969c 437 rcc = response->getFieldAsUInt32(VID_RCC);
0f506caa
VK
438 if (rcc == ERR_SUCCESS)
439 {
b368969c 440 UINT32 count = response->getFieldAsUInt32(VID_NUM_STRINGS);
967893bb 441 for(UINT32 i = 0; i < count; i++)
b368969c 442 value->addPreallocated(response->getFieldAsString(VID_ENUM_VALUE_BASE + i));
0f506caa
VK
443 }
444 delete response;
445 }
446 else
447 {
448 rcc = ERR_INTERNAL_ERROR;
449 }
450 }
451 else
452 {
453 rcc = ERR_CONNECTION_BROKEN;
454 }
455 return rcc;
456}
457
0df58041
VK
458/**
459 * Listener for external subagents
460 */
be44b510
VK
461#ifdef _WIN32
462
204ace22
VK
463static THREAD_RESULT THREAD_CALL ExternalSubagentConnector(void *arg)
464{
465 ExternalSubagent *subagent = (ExternalSubagent *)arg;
466 SECURITY_ATTRIBUTES sa;
467 PSECURITY_DESCRIPTOR sd = NULL;
468 SID_IDENTIFIER_AUTHORITY sidAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
469 EXPLICIT_ACCESS ea;
470 PSID sidEveryone = NULL;
471 ACL *acl = NULL;
472 TCHAR pipeName[MAX_PATH], errorText[1024];
473
474 // Create a well-known SID for the Everyone group.
475 if(!AllocateAndInitializeSid(&sidAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &sidEveryone))
476 {
e5f88e5a
VK
477 nxlog_debug(2, _T("ExternalSubagentConnector(%s): AllocateAndInitializeSid failed (%s)"),
478 subagent->getName(), GetSystemErrorText(GetLastError(), errorText, 1024));
204ace22
VK
479 goto cleanup;
480 }
481
482 // Initialize an EXPLICIT_ACCESS structure for an ACE.
e464b7dc 483 // The ACE will allow either Everyone or given user to access pipe
204ace22
VK
484 ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
485 ea.grfAccessPermissions = (FILE_GENERIC_READ | FILE_GENERIC_WRITE) & ~FILE_CREATE_PIPE_INSTANCE;
486 ea.grfAccessMode = SET_ACCESS;
487 ea.grfInheritance = NO_INHERITANCE;
e464b7dc
VK
488 const TCHAR *user = subagent->getUserName();
489 if ((user[0] == 0) || !_tcscmp(user, _T("*")))
490 {
491 ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
492 ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
493 ea.Trustee.ptstrName = (LPTSTR)sidEveryone;
e5f88e5a 494 nxlog_debug(2, _T("ExternalSubagentConnector(%s): using \"Everyone\" group"), subagent->getName());
e464b7dc
VK
495 }
496 else
497 {
498 ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
499 ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
500 ea.Trustee.ptstrName = (LPTSTR)user;
e5f88e5a 501 nxlog_debug(2, _T("ExternalSubagentConnector(%s): using \"%s\" user"), subagent->getName(), user);
e464b7dc 502 }
204ace22
VK
503
504 // Create a new ACL that contains the new ACEs.
505 if (SetEntriesInAcl(1, &ea, NULL, &acl) != ERROR_SUCCESS)
506 {
e5f88e5a
VK
507 nxlog_debug(2, _T("ExternalSubagentConnector(%s): SetEntriesInAcl failed (%s)"),
508 subagent->getName(), GetSystemErrorText(GetLastError(), errorText, 1024));
204ace22
VK
509 goto cleanup;
510 }
511
512 sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
513 if (sd == NULL)
514 {
e5f88e5a
VK
515 nxlog_debug(2, _T("ExternalSubagentConnector(%s): LocalAlloc failed (%s)"),
516 subagent->getName(), GetSystemErrorText(GetLastError(), errorText, 1024));
204ace22
VK
517 goto cleanup;
518 }
519
520 if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION))
521 {
e5f88e5a
VK
522 nxlog_debug(2, _T("ExternalSubagentConnector(%s): InitializeSecurityDescriptor failed (%s)"),
523 subagent->getName(), GetSystemErrorText(GetLastError(), errorText, 1024));
204ace22
VK
524 goto cleanup;
525 }
526
527 // Add the ACL to the security descriptor.
528 if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE))
529 {
e5f88e5a
VK
530 nxlog_debug(2, _T("ExternalSubagentConnector(%s): SetSecurityDescriptorDacl failed (%s)"),
531 subagent->getName(), GetSystemErrorText(GetLastError(), errorText, 1024));
204ace22
VK
532 goto cleanup;
533 }
534
535 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
536 sa.bInheritHandle = FALSE;
537 sa.lpSecurityDescriptor = sd;
538 _sntprintf(pipeName, MAX_PATH, _T("\\\\.\\pipe\\nxagentd.subagent.%s"), subagent->getName());
0df58041 539 HANDLE hPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 8192, 8192, 0, &sa);
204ace22
VK
540 if (hPipe == INVALID_HANDLE_VALUE)
541 {
e5f88e5a
VK
542 nxlog_debug(2, _T("ExternalSubagentConnector(%s): CreateNamedPipe failed (%s)"),
543 subagent->getName(), GetSystemErrorText(GetLastError(), errorText, 1024));
204ace22
VK
544 goto cleanup;
545 }
546
e5f88e5a 547 nxlog_debug(2, _T("ExternalSubagentConnector(%s): named pipe created, waiting for connection"), subagent->getName());
204ace22
VK
548 int connectErrors = 0;
549 while(!(g_dwFlags & AF_SHUTDOWN))
550 {
551 BOOL connected = ConnectNamedPipe(hPipe, NULL);
552 if (connected || (GetLastError() == ERROR_PIPE_CONNECTED))
553 {
554 subagent->connect(hPipe);
555 DisconnectNamedPipe(hPipe);
556 connectErrors = 0;
557 }
558 else
559 {
e5f88e5a
VK
560 nxlog_debug(2, _T("ExternalSubagentConnector(%s): ConnectNamedPipe failed (%s)"),
561 subagent->getName(), GetSystemErrorText(GetLastError(), errorText, 1024));
204ace22
VK
562 connectErrors++;
563 if (connectErrors > 10)
564 break; // Stop this connector if ConnectNamedPipe fails instantly
565 }
566 }
567
568cleanup:
569 if (hPipe != NULL)
570 CloseHandle(hPipe);
571
572 if (sd != NULL)
573 LocalFree(sd);
574
575 if (acl != NULL)
576 LocalFree(acl);
577
578 if (sidEveryone != NULL)
579 FreeSid(sidEveryone);
580
581 return THREAD_OK;
582}
583
be44b510
VK
584#else
585
586static THREAD_RESULT THREAD_CALL ExternalSubagentConnector(void *arg)
587{
f3c69d69
VK
588 ExternalSubagent *subagent = (ExternalSubagent *)arg;
589 mode_t prevMask = 0;
590
591 int s = socket(AF_UNIX, SOCK_STREAM, 0);
4c0c75c7 592 if (s == INVALID_SOCKET)
f3c69d69 593 {
ac02cfae 594 AgentWriteDebugLog(2, _T("ExternalSubagentConnector: socket failed (%s)"), _tcserror(errno));
f3c69d69
VK
595 goto cleanup;
596 }
597
598 struct sockaddr_un addrLocal;
599 addrLocal.sun_family = AF_UNIX;
600#ifdef UNICODE
e41fc6fc 601 sprintf(addrLocal.sun_path, "/tmp/.nxagentd.subagent.%S", subagent->getName());
f3c69d69 602#else
e41fc6fc 603 sprintf(addrLocal.sun_path, "/tmp/.nxagentd.subagent.%s", subagent->getName());
f3c69d69
VK
604#endif
605 unlink(addrLocal.sun_path);
606 prevMask = umask(S_IWGRP | S_IWOTH);
607 if (bind(s, (struct sockaddr *)&addrLocal, SUN_LEN(&addrLocal)) == -1)
608 {
ac02cfae 609 AgentWriteDebugLog(2, _T("ExternalSubagentConnector: bind failed (%s)"), _tcserror(errno));
f3c69d69
VK
610 umask(prevMask);
611 goto cleanup;
612 }
613 umask(prevMask);
614
615 if (listen(s, 5) == -1)
616 {
ac02cfae 617 AgentWriteDebugLog(2, _T("ExternalSubagentConnector: listen failed (%s)"), _tcserror(errno));
f3c69d69
VK
618 goto cleanup;
619 }
620
621 AgentWriteDebugLog(2, _T("ExternalSubagent(%s): UNIX socket created, waiting for connection"), subagent->getName());
ac02cfae 622 while(!(g_dwFlags & AF_SHUTDOWN))
f3c69d69
VK
623 {
624 struct sockaddr_un addrRemote;
625 socklen_t size = sizeof(struct sockaddr_un);
626 SOCKET cs = accept(s, (struct sockaddr *)&addrRemote, &size);
627 if (cs > 0)
628 {
629 subagent->connect(cs);
630 shutdown(cs, 2);
631 close(cs);
632 }
633 else
634 {
ac02cfae 635 AgentWriteDebugLog(2, _T("ExternalSubagentConnector: accept failed (%s)"), _tcserror(errno));
f3c69d69
VK
636 }
637 }
638
639cleanup:
640 if (s != -1)
641 {
642 close(s);
643 }
644
ac02cfae 645 AgentWriteDebugLog(2, _T("ExternalSubagentConnector: listener thread stopped"));
df9812a9 646 return THREAD_OK;
be44b510
VK
647}
648
649#endif
650
e41fc6fc
VK
651/*
652 * Send message to external subagent
653 */
b368969c 654bool SendMessageToPipe(HPIPE hPipe, NXCP_MESSAGE *msg)
e41fc6fc
VK
655{
656 bool success = false;
657
658#ifdef _WIN32
0137b9f7
VK
659 if (hPipe == INVALID_HANDLE_VALUE)
660 return false;
661
e41fc6fc 662 DWORD bytes = 0;
b368969c 663 if (WriteFile(hPipe, msg, ntohl(msg->size), &bytes, NULL))
e41fc6fc 664 {
b368969c 665 success = (bytes == ntohl(msg->size));
e41fc6fc
VK
666 }
667#else
0137b9f7
VK
668 if (hPipe == -1)
669 return false;
670
b368969c
VK
671 int bytes = SendEx(hPipe, msg, ntohl(msg->size), 0, NULL);
672 success = (bytes == ntohl(msg->size));
e41fc6fc
VK
673#endif
674 return success;
675}
676
0df58041 677/**
e464b7dc
VK
678 * Add external subagent from config.
679 * Each line in config should be in form
680 * name:user
681 * If user part is omited or set to *, connection from any account will be accepted
0df58041 682 */
204ace22
VK
683bool AddExternalSubagent(const TCHAR *config)
684{
e464b7dc
VK
685 TCHAR buffer[1024], user[256] = _T("*");
686
687 nx_strncpy(buffer, config, 1024);
688 TCHAR *ptr = _tcschr(buffer, _T(':'));
689 if (ptr != NULL)
690 {
691 *ptr = 0;
692 ptr++;
693 _tcsncpy(user, ptr, 256);
694 Trim(user);
695 }
696
697 ExternalSubagent *subagent = new ExternalSubagent(buffer, user);
204ace22
VK
698 s_subagents.add(subagent);
699 ThreadCreate(ExternalSubagentConnector, 0, subagent);
700 return true;
701}
0df58041
VK
702
703/**
704 * Add parameters from external providers to NXCP message
705 */
b368969c 706void ListParametersFromExtSubagents(NXCPMessage *msg, UINT32 *baseId, UINT32 *count)
0df58041
VK
707{
708 for(int i = 0; i < s_subagents.size(); i++)
709 {
639088d4
VK
710 if (s_subagents.get(i)->isConnected())
711 {
712 s_subagents.get(i)->listParameters(msg, baseId, count);
713 }
0df58041
VK
714 }
715}
716
717/**
0f506caa 718 * Add parameters from external subagents to string list
0df58041
VK
719 */
720void ListParametersFromExtSubagents(StringList *list)
721{
722 for(int i = 0; i < s_subagents.size(); i++)
723 {
639088d4
VK
724 if (s_subagents.get(i)->isConnected())
725 {
726 s_subagents.get(i)->listParameters(list);
727 }
0df58041
VK
728 }
729}
730
731/**
0f506caa
VK
732 * Add lists from external providers to NXCP message
733 */
b368969c 734void ListListsFromExtSubagents(NXCPMessage *msg, UINT32 *baseId, UINT32 *count)
0f506caa
VK
735{
736 for(int i = 0; i < s_subagents.size(); i++)
737 {
738 if (s_subagents.get(i)->isConnected())
739 {
740 s_subagents.get(i)->listLists(msg, baseId, count);
741 }
742 }
743}
744
745/**
746 * Add lists from external subagents to string list
747 */
748void ListListsFromExtSubagents(StringList *list)
749{
750 for(int i = 0; i < s_subagents.size(); i++)
751 {
752 if (s_subagents.get(i)->isConnected())
753 {
754 s_subagents.get(i)->listLists(list);
755 }
756 }
757}
758
759/**
760 * Add tables from external providers to NXCP message
761 */
b368969c 762void ListTablesFromExtSubagents(NXCPMessage *msg, UINT32 *baseId, UINT32 *count)
0f506caa
VK
763{
764 for(int i = 0; i < s_subagents.size(); i++)
765 {
766 if (s_subagents.get(i)->isConnected())
767 {
768 s_subagents.get(i)->listTables(msg, baseId, count);
769 }
770 }
771}
772
773/**
774 * Add tables from external subagents to string list
775 */
776void ListTablesFromExtSubagents(StringList *list)
777{
778 for(int i = 0; i < s_subagents.size(); i++)
779 {
780 if (s_subagents.get(i)->isConnected())
781 {
782 s_subagents.get(i)->listTables(list);
783 }
784 }
785}
786
787/**
788 * Get value from external subagent
0df58041
VK
789 *
790 * @return agent error code
791 */
967893bb 792UINT32 GetParameterValueFromExtSubagent(const TCHAR *name, TCHAR *buffer)
0df58041 793{
967893bb 794 UINT32 rc = ERR_UNKNOWN_PARAMETER;
0df58041
VK
795 for(int i = 0; i < s_subagents.size(); i++)
796 {
639088d4
VK
797 if (s_subagents.get(i)->isConnected())
798 {
799 rc = s_subagents.get(i)->getParameter(name, buffer);
0f506caa
VK
800 if (rc == ERR_SUCCESS)
801 break;
802 }
803 }
804 return rc;
805}
806
807/**
808 * Get table from external subagent
809 *
810 * @return agent error code
811 */
967893bb 812UINT32 GetTableValueFromExtSubagent(const TCHAR *name, Table *value)
0f506caa 813{
967893bb 814 UINT32 rc = ERR_UNKNOWN_PARAMETER;
0f506caa
VK
815 for(int i = 0; i < s_subagents.size(); i++)
816 {
817 if (s_subagents.get(i)->isConnected())
818 {
819 rc = s_subagents.get(i)->getTable(name, value);
820 if (rc == ERR_SUCCESS)
821 break;
822 }
823 }
824 return rc;
825}
826
827/**
828 * Get list from external subagent
829 *
830 * @return agent error code
831 */
967893bb 832UINT32 GetListValueFromExtSubagent(const TCHAR *name, StringList *value)
0f506caa 833{
967893bb 834 UINT32 rc = ERR_UNKNOWN_PARAMETER;
0f506caa
VK
835 for(int i = 0; i < s_subagents.size(); i++)
836 {
837 if (s_subagents.get(i)->isConnected())
838 {
839 rc = s_subagents.get(i)->getList(name, value);
840 if (rc == ERR_SUCCESS)
639088d4
VK
841 break;
842 }
0df58041
VK
843 }
844 return rc;
845}
f918b160
VK
846
847/**
848 * Shutdown all connected external subagents
849 */
850void ShutdownExtSubagents()
851{
852 for(int i = 0; i < s_subagents.size(); i++)
853 {
854 if (s_subagents.get(i)->isConnected())
855 {
eb17778f 856 nxlog_debug(1, _T("Sending SHUTDOWN command to external subagent %s"), s_subagents.get(i)->getName());
f918b160
VK
857 s_subagents.get(i)->shutdown();
858 }
859 }
860}
eb17778f
VK
861
862/**
863 * Restart all connected external subagents
864 */
865void RestartExtSubagents()
866{
867 for(int i = 0; i < s_subagents.size(); i++)
868 {
869 if (s_subagents.get(i)->isConnected())
870 {
871 nxlog_debug(1, _T("Sending RESTART command to external subagent %s"), s_subagents.get(i)->getName());
872 s_subagents.get(i)->restart();
873 }
874 }
875}