3fa6571e7980fa42ee648a17f0e4f6a5492752b7
[public/netxms.git] / src / libnxcl / session.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Client Library
4 ** Copyright (C) 2004, 2005, 2006, 2007 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: session.cpp
21 **
22 **/
23
24 #include "libnxcl.h"
25
26 #ifdef _WIN32
27 #define close _close
28 #endif
29
30
31 //
32 // Session class constructor
33 //
34
35 NXCL_Session::NXCL_Session()
36 {
37 int i;
38
39 m_dwFlags = 0;
40 m_dwMsgId = 0;
41 m_dwTimeStamp = 0;
42 m_pEventHandler = NULL;
43 m_dwState = STATE_DISCONNECTED;
44 m_dwCommandTimeout = 30000; // Default timeout is 30 seconds
45 m_dwNumObjects = 0;
46 m_pIndexById = NULL;
47 m_mutexIndexAccess = MutexCreate();
48 m_dwReceiverBufferSize = 4194304; // 4MB
49 m_hSocket = -1;
50 m_pItemList = NULL;
51 m_szLastLock[0] = 0;
52 m_pClientData = NULL;
53 m_szServerTimeZone[0] = 0;
54 m_mutexSendMsg = MutexCreate();
55
56 m_ppEventTemplates = NULL;
57 m_dwNumTemplates = 0;
58 m_mutexEventAccess = MutexCreate();
59
60 m_dwNumUsers = 0;
61 m_pUserList = NULL;
62
63 m_hRecvThread = INVALID_THREAD_HANDLE;
64 m_hWatchdogThread = INVALID_THREAD_HANDLE;
65 m_pCtx = NULL;
66
67 m_hCurrFile = -1;
68 m_dwFileRqId = 0;
69 m_condFileRq = ConditionCreate(FALSE);
70 m_mutexFileRq = MutexCreate();
71
72 m_condStopThreads = ConditionCreate(TRUE);
73
74 for(i = 0; i < SYNC_OP_COUNT; i++)
75 {
76 m_mutexSyncOpAccess[i] = MutexCreate();
77 m_dwSyncExitCode[i] = 0;
78 #ifdef _WIN32
79 m_condSyncOp[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
80 #else
81 pthread_mutex_init(&m_mutexSyncOp[i], NULL);
82 pthread_cond_init(&m_condSyncOp[i], NULL);
83 m_bSyncFinished[i] = FALSE;
84 #endif
85 }
86 }
87
88
89 //
90 // Session class destructor
91 //
92
93 NXCL_Session::~NXCL_Session()
94 {
95 int i;
96
97 disconnect();
98
99 // Wait for receiver thread termination
100 if (m_hRecvThread != INVALID_THREAD_HANDLE)
101 ThreadJoin(m_hRecvThread);
102
103 MutexDestroy(m_mutexIndexAccess);
104
105 MutexLock(m_mutexEventAccess, INFINITE);
106 MutexUnlock(m_mutexEventAccess);
107 MutexDestroy(m_mutexEventAccess);
108
109 ConditionSet(m_condFileRq);
110 MutexLock(m_mutexFileRq, INFINITE);
111 MutexUnlock(m_mutexFileRq);
112 MutexDestroy(m_mutexFileRq);
113 ConditionDestroy(m_condFileRq);
114
115 ConditionDestroy(m_condStopThreads);
116
117 for(i = 0; i < SYNC_OP_COUNT; i++)
118 {
119 MutexDestroy(m_mutexSyncOpAccess[i]);
120 #ifdef _WIN32
121 CloseHandle(m_condSyncOp[i]);
122 #else
123 pthread_mutex_destroy(&m_mutexSyncOp[i]);
124 pthread_cond_destroy(&m_condSyncOp[i]);
125 #endif
126 }
127
128 MutexDestroy(m_mutexSendMsg);
129
130 DestroyEncryptionContext(m_pCtx);
131 }
132
133
134 //
135 // Disconnect session
136 //
137
138 void NXCL_Session::disconnect()
139 {
140 // Terminate watchdog thread
141 ConditionSet(m_condStopThreads);
142 if (m_hWatchdogThread != INVALID_THREAD_HANDLE)
143 {
144 ThreadJoin(m_hWatchdogThread);
145 m_hWatchdogThread = INVALID_THREAD_HANDLE;
146 }
147 ConditionReset(m_condStopThreads);
148
149 // Close socket
150 shutdown(m_hSocket, SHUT_RDWR);
151 closesocket(m_hSocket);
152 m_hSocket = -1;
153
154 // Clear message wait queue
155 m_msgWaitQueue.Clear();
156
157 // Cleanup
158 destroyAllObjects();
159 destroyEventDB();
160 destroyUserDB();
161
162 DestroyEncryptionContext(m_pCtx);
163 m_pCtx = NULL;
164 }
165
166
167 //
168 // Destroy all objects
169 //
170
171 void NXCL_Session::destroyAllObjects()
172 {
173 DWORD i;
174
175 MutexLock(m_mutexIndexAccess, INFINITE);
176 for(i = 0; i < m_dwNumObjects; i++)
177 DestroyObject(m_pIndexById[i].pObject);
178 m_dwNumObjects = 0;
179 safe_free(m_pIndexById);
180 m_pIndexById = NULL;
181 MutexUnlock(m_mutexIndexAccess);
182 }
183
184
185 //
186 // Wait for specific message
187 //
188
189 CSCPMessage *NXCL_Session::WaitForMessage(WORD wCode, DWORD dwId, DWORD dwTimeOut)
190 {
191 if (m_dwFlags & NXC_SF_CONN_BROKEN)
192 return NULL;
193 return m_msgWaitQueue.WaitForMessage(wCode, dwId,
194 dwTimeOut == 0 ? m_dwCommandTimeout : dwTimeOut);
195 }
196
197
198 //
199 // Wait for specific raw message
200 //
201
202 CSCP_MESSAGE *NXCL_Session::WaitForRawMessage(WORD wCode, DWORD dwId, DWORD dwTimeOut)
203 {
204 if (m_dwFlags & NXC_SF_CONN_BROKEN)
205 return NULL;
206 return m_msgWaitQueue.WaitForRawMessage(wCode, dwId,
207 dwTimeOut == 0 ? m_dwCommandTimeout : dwTimeOut);
208 }
209
210
211 //
212 // Wait for request completion notification and extract result code
213 // from recived message
214 //
215
216 DWORD NXCL_Session::WaitForRCC(DWORD dwRqId, DWORD dwTimeOut)
217 {
218 CSCPMessage *pResponse;
219 DWORD dwRetCode;
220
221 if (m_dwFlags & NXC_SF_CONN_BROKEN)
222 {
223 dwRetCode = RCC_CONNECTION_BROKEN;
224 }
225 else
226 {
227 pResponse = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, dwTimeOut);
228 if (pResponse != NULL)
229 {
230 dwRetCode = pResponse->GetVariableLong(VID_RCC);
231 if (dwRetCode == RCC_COMPONENT_LOCKED)
232 {
233 _tcscpy(m_szLastLock, _T("<unknown>"));
234 if (pResponse->IsVariableExist(VID_LOCKED_BY))
235 {
236 pResponse->GetVariableStr(VID_LOCKED_BY, m_szLastLock, MAX_LOCKINFO_LEN);
237 }
238 }
239 delete pResponse;
240 }
241 else
242 {
243 dwRetCode = RCC_TIMEOUT;
244 }
245 }
246 return dwRetCode;
247 }
248
249
250 //
251 // Send CSCP message
252 //
253
254 BOOL NXCL_Session::SendMsg(CSCPMessage *pMsg)
255 {
256 CSCP_MESSAGE *pRawMsg;
257 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
258 BOOL bResult;
259 TCHAR szBuffer[128];
260
261 if (m_dwFlags & NXC_SF_CONN_BROKEN)
262 return FALSE;
263
264 DebugPrintf(_T("SendMsg(\"%s\", id:%d)"), NXCPMessageCodeName(pMsg->GetCode(), szBuffer), pMsg->GetId());
265 pRawMsg = pMsg->CreateMessage();
266 MutexLock(m_mutexSendMsg, INFINITE);
267 if (m_pCtx != NULL)
268 {
269 pEnMsg = CSCPEncryptMessage(m_pCtx, pRawMsg);
270 if (pEnMsg != NULL)
271 {
272 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) == (int)ntohl(pEnMsg->dwSize));
273 free(pEnMsg);
274 }
275 else
276 {
277 bResult = FALSE;
278 }
279 }
280 else
281 {
282 bResult = (SendEx(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
283 }
284 MutexUnlock(m_mutexSendMsg);
285 free(pRawMsg);
286 return bResult;
287 }
288
289
290 //
291 // Wait for synchronization operation completion
292 //
293
294 DWORD NXCL_Session::WaitForSync(int nSyncOp, DWORD dwTimeOut)
295 {
296 #ifdef _WIN32
297 DWORD dwRetCode;
298
299 dwRetCode = WaitForSingleObject(m_condSyncOp[nSyncOp], dwTimeOut);
300 MutexUnlock(m_mutexSyncOpAccess[nSyncOp]);
301 return (dwRetCode == WAIT_TIMEOUT) ? RCC_TIMEOUT : m_dwSyncExitCode[nSyncOp];
302 #else
303 int iRetCode;
304 DWORD dwResult;
305
306 pthread_mutex_lock(&m_mutexSyncOp[nSyncOp]);
307 if (!m_bSyncFinished[nSyncOp])
308 {
309 if (dwTimeOut != INFINITE)
310 {
311 #if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP
312 struct timespec timeout;
313
314 timeout.tv_sec = dwTimeOut / 1000;
315 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
316 iRetCode = pthread_cond_reltimedwait_np(&m_condSyncOp[nSyncOp], &m_mutexSyncOp[nSyncOp], &timeout);
317 #else
318 struct timeval now;
319 struct timespec timeout;
320
321 gettimeofday(&now, NULL);
322 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
323 timeout.tv_nsec = (now.tv_usec + (dwTimeOut % 1000) * 1000) * 1000;
324 iRetCode = pthread_cond_timedwait(&m_condSyncOp[nSyncOp], &m_mutexSyncOp[nSyncOp], &timeout);
325 #endif
326 }
327 else
328 {
329 iRetCode = pthread_cond_wait(&m_condSyncOp[nSyncOp], &m_mutexSyncOp[nSyncOp]);
330 }
331 dwResult = (iRetCode == 0) ? m_dwSyncExitCode[nSyncOp] : RCC_TIMEOUT;
332 }
333 else
334 {
335 dwResult = m_dwSyncExitCode[nSyncOp];
336 }
337 pthread_mutex_unlock(&m_mutexSyncOp[nSyncOp]);
338 MutexUnlock(m_mutexSyncOpAccess[nSyncOp]);
339 return dwResult;
340 #endif
341 }
342
343
344 //
345 // Prepare for synchronization operation
346 //
347
348 void NXCL_Session::PrepareForSync(int nSyncOp)
349 {
350 MutexLock(m_mutexSyncOpAccess[nSyncOp], INFINITE);
351 m_dwSyncExitCode[nSyncOp] = RCC_SYSTEM_FAILURE;
352 #ifdef _WIN32
353 ResetEvent(m_condSyncOp[nSyncOp]);
354 #else
355 m_bSyncFinished[nSyncOp] = FALSE;
356 #endif
357 }
358
359
360 //
361 // Complete synchronization operation
362 //
363
364 void NXCL_Session::CompleteSync(int nSyncOp, DWORD dwRetCode)
365 {
366 #ifdef _WIN32
367 m_dwSyncExitCode[nSyncOp] = dwRetCode;
368 SetEvent(m_condSyncOp[nSyncOp]);
369 #else
370 pthread_mutex_lock(&m_mutexSyncOp[nSyncOp]);
371 m_dwSyncExitCode[nSyncOp] = dwRetCode;
372 m_bSyncFinished[nSyncOp] = TRUE;
373 pthread_cond_signal(&m_condSyncOp[nSyncOp]);
374 pthread_mutex_unlock(&m_mutexSyncOp[nSyncOp]);
375 #endif
376 }
377
378
379 //
380 // Process DCIs coming from server
381 //
382
383 void NXCL_Session::processDCI(CSCPMessage *pMsg)
384 {
385 if (pMsg->IsEndOfSequence())
386 {
387 CompleteSync(SYNC_DCI_LIST, RCC_SUCCESS);
388 }
389 else if (m_pItemList != NULL)
390 {
391 DWORD i, j, dwId;
392
393 i = m_pItemList->dwNumItems;
394 m_pItemList->dwNumItems++;
395 m_pItemList->pItems = (NXC_DCI *)realloc(m_pItemList->pItems,
396 sizeof(NXC_DCI) * m_pItemList->dwNumItems);
397 m_pItemList->pItems[i].dwId = pMsg->GetVariableLong(VID_DCI_ID);
398 m_pItemList->pItems[i].dwTemplateId = pMsg->GetVariableLong(VID_TEMPLATE_ID);
399 m_pItemList->pItems[i].dwResourceId = pMsg->GetVariableLong(VID_RESOURCE_ID);
400 m_pItemList->pItems[i].dwProxyNode = pMsg->GetVariableLong(VID_PROXY_NODE);
401 m_pItemList->pItems[i].iDataType = (BYTE)pMsg->GetVariableShort(VID_DCI_DATA_TYPE);
402 m_pItemList->pItems[i].iPollingInterval = (int)pMsg->GetVariableLong(VID_POLLING_INTERVAL);
403 m_pItemList->pItems[i].iRetentionTime = (int)pMsg->GetVariableLong(VID_RETENTION_TIME);
404 m_pItemList->pItems[i].iSource = (BYTE)pMsg->GetVariableShort(VID_DCI_SOURCE_TYPE);
405 m_pItemList->pItems[i].iStatus = (BYTE)pMsg->GetVariableShort(VID_DCI_STATUS);
406 m_pItemList->pItems[i].iDeltaCalculation = (BYTE)pMsg->GetVariableShort(VID_DCI_DELTA_CALCULATION);
407 m_pItemList->pItems[i].iProcessAllThresholds = (BYTE)pMsg->GetVariableShort(VID_ALL_THRESHOLDS);
408 m_pItemList->pItems[i].iAdvSchedule = (BYTE)pMsg->GetVariableShort(VID_ADV_SCHEDULE);
409 m_pItemList->pItems[i].pszFormula = pMsg->GetVariableStr(VID_DCI_FORMULA);
410 pMsg->GetVariableStr(VID_NAME, m_pItemList->pItems[i].szName, MAX_ITEM_NAME);
411 pMsg->GetVariableStr(VID_DESCRIPTION, m_pItemList->pItems[i].szDescription, MAX_DB_STRING);
412 pMsg->GetVariableStr(VID_INSTANCE, m_pItemList->pItems[i].szInstance, MAX_DB_STRING);
413 pMsg->GetVariableStr(VID_SYSTEM_TAG, m_pItemList->pItems[i].szSystemTag, MAX_DB_STRING);
414 m_pItemList->pItems[i].nBaseUnits = (int)pMsg->GetVariableShort(VID_BASE_UNITS);
415 m_pItemList->pItems[i].nMultiplier = (int)pMsg->GetVariableLong(VID_MULTIPLIER);
416 m_pItemList->pItems[i].pszCustomUnitName = pMsg->GetVariableStr(VID_CUSTOM_UNITS_NAME);
417 m_pItemList->pItems[i].pszPerfTabSettings = pMsg->GetVariableStr(VID_PERFTAB_SETTINGS);
418 m_pItemList->pItems[i].dwNumSchedules = pMsg->GetVariableLong(VID_NUM_SCHEDULES);
419 m_pItemList->pItems[i].ppScheduleList = (TCHAR **)malloc(sizeof(TCHAR *) * m_pItemList->pItems[i].dwNumSchedules);
420 for(j = 0, dwId = VID_DCI_SCHEDULE_BASE; j < m_pItemList->pItems[i].dwNumSchedules; j++, dwId++)
421 m_pItemList->pItems[i].ppScheduleList[j] = pMsg->GetVariableStr(dwId);
422 m_pItemList->pItems[i].dwNumThresholds = pMsg->GetVariableLong(VID_NUM_THRESHOLDS);
423 m_pItemList->pItems[i].pThresholdList =
424 (NXC_DCI_THRESHOLD *)malloc(sizeof(NXC_DCI_THRESHOLD) * m_pItemList->pItems[i].dwNumThresholds);
425 for(j = 0, dwId = VID_DCI_THRESHOLD_BASE; j < m_pItemList->pItems[i].dwNumThresholds; j++, dwId++)
426 {
427 m_pItemList->pItems[i].pThresholdList[j].dwId = pMsg->GetVariableLong(dwId++);
428 m_pItemList->pItems[i].pThresholdList[j].dwEvent = pMsg->GetVariableLong(dwId++);
429 m_pItemList->pItems[i].pThresholdList[j].dwRearmEvent = pMsg->GetVariableLong(dwId++);
430 m_pItemList->pItems[i].pThresholdList[j].wFunction = pMsg->GetVariableShort(dwId++);
431 m_pItemList->pItems[i].pThresholdList[j].wOperation = pMsg->GetVariableShort(dwId++);
432 m_pItemList->pItems[i].pThresholdList[j].dwArg1 = pMsg->GetVariableLong(dwId++);
433 m_pItemList->pItems[i].pThresholdList[j].dwArg2 = pMsg->GetVariableLong(dwId++);
434 m_pItemList->pItems[i].pThresholdList[j].nRepeatInterval = (LONG)pMsg->GetVariableLong(dwId++);
435 pMsg->GetVariableStr(dwId++, m_pItemList->pItems[i].pThresholdList[j].szValue, MAX_STRING_VALUE);
436 }
437 }
438 }
439
440
441 //
442 // Load data collection items list for specified node
443 // This function is NOT REENTRANT
444 //
445
446 DWORD NXCL_Session::OpenNodeDCIList(DWORD dwNodeId, NXC_DCI_LIST **ppItemList)
447 {
448 CSCPMessage msg;
449 DWORD dwRetCode, dwRqId;
450
451 dwRqId = CreateRqId();
452 PrepareForSync(SYNC_DCI_LIST);
453
454 m_pItemList = (NXC_DCI_LIST *)malloc(sizeof(NXC_DCI_LIST));
455 m_pItemList->dwNodeId = dwNodeId;
456 m_pItemList->dwNumItems = 0;
457 m_pItemList->pItems = NULL;
458
459 msg.SetCode(CMD_GET_NODE_DCI_LIST);
460 msg.SetId(dwRqId);
461 msg.SetVariable(VID_OBJECT_ID, dwNodeId);
462 SendMsg(&msg);
463
464 dwRetCode = WaitForRCC(dwRqId);
465
466 if (dwRetCode == RCC_SUCCESS)
467 {
468 // Wait for DCI list end or for disconnection
469 dwRetCode = WaitForSync(SYNC_DCI_LIST, INFINITE);
470 if (dwRetCode == RCC_SUCCESS)
471 {
472 *ppItemList = m_pItemList;
473 }
474 else
475 {
476 free(m_pItemList);
477 }
478 }
479 else
480 {
481 UnlockSyncOp(SYNC_DCI_LIST);
482 free(m_pItemList);
483 }
484
485 m_pItemList = NULL;
486 return dwRetCode;
487 }
488
489
490 //
491 // Load event configuration database
492 //
493
494 DWORD NXCL_Session::LoadEventDB(void)
495 {
496 CSCPMessage msg;
497 DWORD dwRetCode, dwRqId;
498
499 dwRqId = CreateRqId();
500 PrepareForSync(SYNC_EVENT_DB);
501
502 destroyEventDB();
503 MutexLock(m_mutexEventAccess, INFINITE);
504
505 msg.SetCode(CMD_LOAD_EVENT_DB);
506 msg.SetId(dwRqId);
507 SendMsg(&msg);
508
509 dwRetCode = WaitForRCC(dwRqId);
510
511 /* TODO: this probably should be recoded as loop with calls to WaitForMessage() */
512 if (dwRetCode == RCC_SUCCESS)
513 dwRetCode = WaitForSync(SYNC_EVENT_DB, INFINITE);
514 else
515 UnlockSyncOp(SYNC_EVENT_DB);
516
517 MutexUnlock(m_mutexEventAccess);
518 return dwRetCode;
519 }
520
521
522 //
523 // Destroy event template database
524 //
525
526 void NXCL_Session::destroyEventDB()
527 {
528 DWORD i;
529
530 for(i = 0; i < m_dwNumTemplates; i++)
531 {
532 safe_free(m_ppEventTemplates[i]->pszDescription);
533 safe_free(m_ppEventTemplates[i]->pszMessage);
534 free(m_ppEventTemplates[i]);
535 }
536 safe_free(m_ppEventTemplates);
537 m_dwNumTemplates = 0;
538 m_ppEventTemplates = NULL;
539 }
540
541
542 //
543 // Delete record from list
544 //
545
546 void NXCL_Session::DeleteEDBRecord(DWORD dwEventCode)
547 {
548 DWORD i;
549
550 MutexLock(m_mutexEventAccess, INFINITE);
551 for(i = 0; i < m_dwNumTemplates; i++)
552 if (m_ppEventTemplates[i]->dwCode == dwEventCode)
553 {
554 m_dwNumTemplates--;
555 safe_free(m_ppEventTemplates[i]->pszDescription);
556 safe_free(m_ppEventTemplates[i]->pszMessage);
557 free(m_ppEventTemplates[i]);
558 memmove(&m_ppEventTemplates[i], m_ppEventTemplates[i + 1],
559 sizeof(NXC_EVENT_TEMPLATE *) * (m_dwNumTemplates - i));
560 break;
561 }
562 MutexUnlock(m_mutexEventAccess);
563 }
564
565
566 //
567 // Add template to list
568 //
569
570 void NXCL_Session::AddEventTemplate(NXC_EVENT_TEMPLATE *pEventTemplate, BOOL bLock)
571 {
572 if (bLock)
573 MutexLock(m_mutexEventAccess, INFINITE);
574 m_ppEventTemplates = (NXC_EVENT_TEMPLATE **)realloc(m_ppEventTemplates,
575 sizeof(NXC_EVENT_TEMPLATE *) * (m_dwNumTemplates + 1));
576 m_ppEventTemplates[m_dwNumTemplates] = pEventTemplate;
577 m_dwNumTemplates++;
578 if (bLock)
579 MutexUnlock(m_mutexEventAccess);
580 }
581
582
583 //
584 // Get pointer to event templates list
585 //
586
587 BOOL NXCL_Session::GetEventDB(NXC_EVENT_TEMPLATE ***pppTemplateList, DWORD *pdwNumRecords)
588 {
589 *pppTemplateList = m_ppEventTemplates;
590 *pdwNumRecords = m_dwNumTemplates;
591 return TRUE;
592 }
593
594
595 //
596 // Resolve event id to name
597 //
598
599 const TCHAR *NXCL_Session::GetEventName(DWORD dwId)
600 {
601 DWORD i;
602
603 MutexLock(m_mutexEventAccess, INFINITE);
604 for(i = 0; i < m_dwNumTemplates; i++)
605 if (m_ppEventTemplates[i]->dwCode == dwId)
606 {
607 MutexUnlock(m_mutexEventAccess);
608 return m_ppEventTemplates[i]->szName;
609 }
610 MutexUnlock(m_mutexEventAccess);
611 return _T("<unknown>");
612 }
613
614
615 //
616 // Resolve event id to name using application-provided buffer
617 //
618
619 BOOL NXCL_Session::GetEventNameEx(DWORD dwId, TCHAR *pszBuffer, DWORD dwBufSize)
620 {
621 DWORD i;
622
623 MutexLock(m_mutexEventAccess, INFINITE);
624 for(i = 0; i < m_dwNumTemplates; i++)
625 if (m_ppEventTemplates[i]->dwCode == dwId)
626 {
627 nx_strncpy(pszBuffer, m_ppEventTemplates[i]->szName, dwBufSize);
628 MutexUnlock(m_mutexEventAccess);
629 return TRUE;
630 }
631 MutexUnlock(m_mutexEventAccess);
632 *pszBuffer = 0;
633 return FALSE;
634 }
635
636
637 //
638 // Get severity for given event id. Will return -1 for unknown id.
639 //
640
641 int NXCL_Session::GetEventSeverity(DWORD dwId)
642 {
643 DWORD i;
644
645 MutexLock(m_mutexEventAccess, INFINITE);
646 for(i = 0; i < m_dwNumTemplates; i++)
647 if (m_ppEventTemplates[i]->dwCode == dwId)
648 {
649 MutexUnlock(m_mutexEventAccess);
650 return (int)(m_ppEventTemplates[i]->dwSeverity);
651 }
652 MutexUnlock(m_mutexEventAccess);
653 return -1;
654 }
655
656
657 //
658 // Get text of event template with given ID.
659 // If there are no template with such ID, empty string will be returned.
660 //
661
662 BOOL NXCL_Session::GetEventText(DWORD dwId, TCHAR *pszBuffer, DWORD dwBufSize)
663 {
664 DWORD i;
665
666 MutexLock(m_mutexEventAccess, INFINITE);
667 for(i = 0; i < m_dwNumTemplates; i++)
668 if (m_ppEventTemplates[i]->dwCode == dwId)
669 {
670 nx_strncpy(pszBuffer, m_ppEventTemplates[i]->pszMessage, dwBufSize);
671 MutexUnlock(m_mutexEventAccess);
672 return TRUE;
673 }
674 MutexUnlock(m_mutexEventAccess);
675 *pszBuffer = 0;
676 return FALSE;
677 }
678
679
680 //
681 // Destroy user database
682 //
683
684 void NXCL_Session::destroyUserDB()
685 {
686 DWORD i;
687
688 for(i = 0; i < m_dwNumUsers; i++)
689 safe_free(m_pUserList[i].pdwMemberList);
690 safe_free(m_pUserList);
691 m_pUserList = NULL;
692 m_dwNumUsers = 0;
693 m_dwFlags &= ~NXC_SF_USERDB_LOADED;
694 }
695
696
697 //
698 // Process user record from network
699 //
700
701 void NXCL_Session::processUserDBRecord(CSCPMessage *pMsg)
702 {
703 switch(pMsg->GetCode())
704 {
705 case CMD_USER_DB_EOF:
706 CompleteSync(SYNC_USER_DB, RCC_SUCCESS);
707 break;
708 case CMD_USER_DATA:
709 case CMD_GROUP_DATA:
710 m_pUserList = (NXC_USER *)realloc(m_pUserList, sizeof(NXC_USER) * (m_dwNumUsers + 1));
711 memset(&m_pUserList[m_dwNumUsers], 0, sizeof(NXC_USER));
712 UpdateUserFromMessage(pMsg, &m_pUserList[m_dwNumUsers]);
713 m_dwNumUsers++;
714 break;
715 default:
716 break;
717 }
718 }
719
720
721 //
722 // Process user database update
723 //
724
725 void NXCL_Session::processUserDBUpdate(CSCPMessage *pMsg)
726 {
727 int iCode;
728 DWORD dwUserId;
729 NXC_USER *pUser;
730
731 iCode = pMsg->GetVariableShort(VID_UPDATE_TYPE);
732 dwUserId = pMsg->GetVariableLong(VID_USER_ID);
733 pUser = FindUserById(dwUserId);
734
735 switch(iCode)
736 {
737 case USER_DB_CREATE:
738 if (pUser == NULL)
739 {
740 // No user with this id, create one
741 m_pUserList = (NXC_USER *)realloc(m_pUserList, sizeof(NXC_USER) * (m_dwNumUsers + 1));
742 memset(&m_pUserList[m_dwNumUsers], 0, sizeof(NXC_USER));
743
744 // Process common fields
745 m_pUserList[m_dwNumUsers].dwId = dwUserId;
746 pMsg->GetVariableStr(VID_USER_NAME, m_pUserList[m_dwNumUsers].szName, MAX_USER_NAME);
747 pUser = &m_pUserList[m_dwNumUsers];
748 m_dwNumUsers++;
749 }
750 break;
751 case USER_DB_MODIFY:
752 if (pUser == NULL)
753 {
754 // No user with this id, create one
755 m_pUserList = (NXC_USER *)realloc(m_pUserList, sizeof(NXC_USER) * (m_dwNumUsers + 1));
756 memset(&m_pUserList[m_dwNumUsers], 0, sizeof(NXC_USER));
757 pUser = &m_pUserList[m_dwNumUsers];
758 m_dwNumUsers++;
759 }
760 UpdateUserFromMessage(pMsg, pUser);
761 break;
762 case USER_DB_DELETE:
763 if (pUser != NULL)
764 pUser->wFlags |= UF_DELETED;
765 break;
766 default:
767 break;
768 }
769
770 if (pUser != NULL)
771 callEventHandler(NXC_EVENT_USER_DB_CHANGED, iCode, pUser);
772 }
773
774
775 //
776 // Find user in database by ID
777 //
778
779 NXC_USER *NXCL_Session::FindUserById(DWORD dwId)
780 {
781 DWORD i;
782 NXC_USER *pUser = NULL;
783
784 if (m_dwFlags & NXC_SF_USERDB_LOADED)
785 {
786 for(i = 0; i < m_dwNumUsers; i++)
787 if (m_pUserList[i].dwId == dwId)
788 {
789 pUser = &m_pUserList[i];
790 break;
791 }
792 }
793
794 return pUser;
795 }
796
797
798 //
799 // Get pointer to user list and number of users
800 //
801
802 BOOL NXCL_Session::GetUserDB(NXC_USER **ppUserList, DWORD *pdwNumUsers)
803 {
804 if (!(m_dwFlags & NXC_SF_USERDB_LOADED))
805 return FALSE;
806
807 *ppUserList = m_pUserList;
808 *pdwNumUsers = m_dwNumUsers;
809 return TRUE;
810 }
811
812
813 //
814 // Load user database
815 // This function is NOT REENTRANT
816 //
817
818 DWORD NXCL_Session::LoadUserDB(void)
819 {
820 CSCPMessage msg;
821 DWORD dwRetCode, dwRqId;
822
823 dwRqId = CreateRqId();
824 PrepareForSync(SYNC_USER_DB);
825 destroyUserDB();
826
827 msg.SetCode(CMD_LOAD_USER_DB);
828 msg.SetId(dwRqId);
829 SendMsg(&msg);
830
831 dwRetCode = WaitForRCC(dwRqId);
832
833 if (dwRetCode == RCC_SUCCESS)
834 {
835 dwRetCode = WaitForSync(SYNC_USER_DB, INFINITE);
836 if (dwRetCode == RCC_SUCCESS)
837 m_dwFlags |= NXC_SF_USERDB_LOADED;
838 }
839 else
840 {
841 UnlockSyncOp(SYNC_USER_DB);
842 }
843
844 return dwRetCode;
845 }
846
847
848 //
849 // Send file to server
850 //
851
852 DWORD NXCL_Session::SendFile(DWORD dwRqId, TCHAR *pszFileName)
853 {
854 return SendFileOverNXCP(m_hSocket, dwRqId, pszFileName, m_pCtx, 0, NULL, NULL) ? RCC_SUCCESS : RCC_IO_ERROR;
855 }
856
857
858 //
859 // Set subscription status for given channel(s)
860 //
861
862 DWORD NXCL_Session::SetSubscriptionStatus(DWORD dwChannels, int nOperation)
863 {
864 CSCPMessage msg;
865 DWORD dwRqId;
866
867 dwRqId = CreateRqId();
868
869 msg.SetCode(CMD_CHANGE_SUBSCRIPTION);
870 msg.SetId(dwRqId);
871 msg.SetVariable(VID_FLAGS, dwChannels);
872 msg.SetVariable(VID_OPERATION, (WORD)nOperation);
873 SendMsg(&msg);
874
875 return WaitForRCC(dwRqId);
876 }
877
878
879 //
880 // Prepares file transfer from server to client
881 //
882
883 DWORD NXCL_Session::PrepareFileTransfer(const TCHAR *pszFile, DWORD dwRqId)
884 {
885 DWORD dwResult;
886
887 MutexLock(m_mutexFileRq, INFINITE);
888 if (m_hCurrFile == -1)
889 {
890 m_hCurrFile = _topen(pszFile, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY,
891 S_IRUSR | S_IWUSR);
892 dwResult = (m_hCurrFile != -1) ? RCC_SUCCESS : RCC_FILE_IO_ERROR;
893 m_dwFileRqId = dwRqId;
894 ConditionReset(m_condFileRq);
895 }
896 else
897 {
898 dwResult = RCC_TRANSFER_IN_PROGRESS;
899 }
900 MutexUnlock(m_mutexFileRq);
901 return dwResult;
902 }
903
904
905 //
906 // Wait for file transfer completion
907 //
908
909 DWORD NXCL_Session::WaitForFileTransfer(DWORD dwTimeout)
910 {
911 DWORD dwResult;
912 BOOL bSuccess;
913
914 MutexLock(m_mutexFileRq, INFINITE);
915 if (m_hCurrFile != -1)
916 {
917 MutexUnlock(m_mutexFileRq);
918 bSuccess = ConditionWait(m_condFileRq, dwTimeout);
919 MutexLock(m_mutexFileRq, INFINITE);
920 if (bSuccess)
921 {
922 dwResult = m_dwFileRqCompletion;
923 }
924 else
925 {
926 dwResult = RCC_TIMEOUT;
927 if (m_hCurrFile != -1)
928 close(m_hCurrFile);
929 }
930 m_hCurrFile = -1;
931 }
932 else
933 {
934 dwResult = RCC_INCOMPATIBLE_OPERATION;
935 }
936 MutexUnlock(m_mutexFileRq);
937 return dwResult;
938 }
939
940
941 //
942 // Abort file transfer
943 //
944
945 void NXCL_Session::AbortFileTransfer(void)
946 {
947 MutexLock(m_mutexFileRq, INFINITE);
948 if (m_hCurrFile != -1)
949 {
950 close(m_hCurrFile);
951 m_hCurrFile = -1;
952 m_dwFileRqId = 0;
953 }
954 MutexUnlock(m_mutexFileRq);
955 }
956
957
958 //
959 // Execute simple command (command without arguments and returnning only RCC)
960 //
961
962 DWORD NXCL_Session::SimpleCommand(WORD wCmd)
963 {
964 CSCPMessage msg;
965 DWORD dwRqId;
966
967 dwRqId = CreateRqId();
968
969 msg.SetCode(wCmd);
970 msg.SetId(dwRqId);
971 SendMsg(&msg);
972
973 return WaitForRCC(dwRqId);
974 }
975
976
977 //
978 // Parse login response message
979 //
980
981 void NXCL_Session::ParseLoginMessage(CSCPMessage *pMsg)
982 {
983 m_dwUserId = pMsg->GetVariableLong(VID_USER_ID);
984 m_dwSystemAccess = pMsg->GetVariableLong(VID_USER_SYS_RIGHTS);
985 if (pMsg->GetVariableShort(VID_CHANGE_PASSWD_FLAG))
986 m_dwFlags |= NXC_SF_CHANGE_PASSWD;
987 if (!pMsg->GetVariableShort(VID_DBCONN_STATUS))
988 m_dwFlags |= NXC_SF_BAD_DBCONN;
989 }
990
991
992 //
993 // Start watchdog thread
994 //
995
996 void NXCL_Session::StartWatchdogThread()
997 {
998 if (m_hWatchdogThread == INVALID_THREAD_HANDLE)
999 m_hWatchdogThread = ThreadCreateEx(NXCL_Session::watchdogThreadStarter, 0, this);
1000 }
1001
1002
1003 //
1004 // Starter function for watchdog thread
1005 //
1006
1007 THREAD_RESULT THREAD_CALL NXCL_Session::watchdogThreadStarter(void *pArg)
1008 {
1009 ((NXCL_Session *)pArg)->watchdogThread();
1010 return THREAD_OK;
1011 }
1012
1013
1014 //
1015 // Watchdog thread
1016 //
1017
1018 void NXCL_Session::watchdogThread()
1019 {
1020 CSCPMessage msg;
1021 DWORD dwRqId;
1022 BOOL bConnBroken = FALSE;
1023
1024 msg.SetCode(CMD_KEEPALIVE);
1025 while(1)
1026 {
1027 if (ConditionWait(m_condStopThreads, 30000))
1028 break; // Need to stop
1029
1030 // Send keepalive message
1031 dwRqId = CreateRqId();
1032 msg.SetId(dwRqId);
1033
1034 if (SendMsg(&msg))
1035 {
1036 if (WaitForRCC(dwRqId) != RCC_SUCCESS)
1037 {
1038 bConnBroken = TRUE;
1039 }
1040 }
1041 else
1042 {
1043 bConnBroken = TRUE;
1044 }
1045
1046 if (bConnBroken)
1047 {
1048 m_dwFlags |= NXC_SF_CONN_BROKEN;
1049 callEventHandler(NXC_EVENT_CONNECTION_BROKEN, 0, NULL);
1050 break;
1051 }
1052 }
1053 }
1054
1055
1056 //
1057 // Handler for CMD_NOTIFY message
1058 //
1059
1060 void NXCL_Session::OnNotify(CSCPMessage *pMsg)
1061 {
1062 DWORD dwCode;
1063
1064 dwCode = pMsg->GetVariableLong(VID_NOTIFICATION_CODE);
1065 if (dwCode == NX_NOTIFY_SHUTDOWN)
1066 {
1067 // Stop watchdog and set broken connection flag
1068 ConditionSet(m_condStopThreads);
1069 if (m_hWatchdogThread != INVALID_THREAD_HANDLE)
1070 {
1071 ThreadJoin(m_hWatchdogThread);
1072 m_hWatchdogThread = INVALID_THREAD_HANDLE;
1073 }
1074 ConditionReset(m_condStopThreads);
1075 m_dwFlags |= NXC_SF_CONN_BROKEN;
1076 }
1077 callEventHandler(NXC_EVENT_NOTIFICATION, dwCode,
1078 CAST_TO_POINTER(pMsg->GetVariableLong(VID_NOTIFICATION_DATA), void *));
1079 }