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