- Finished migration to new client library model
[public/netxms.git] / src / libnxcl / session.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Client Library
4 ** Copyright (C) 2004 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 ** $module: session.cpp
21 **
22 **/
23
24 #include "libnxcl.h"
25
26
27 //
28 // Session class constructor
29 //
30
31 NXCL_Session::NXCL_Session()
32 {
33 m_dwFlags = 0;
34 m_dwMsgId = 0;
35 m_pEventHandler = NULL;
36 m_dwState = STATE_DISCONNECTED;
37 m_dwCommandTimeout = 10000; // Default timeout is 10 seconds
38 m_dwNumObjects = 0;
39 m_pIndexById = NULL;
40 m_mutexIndexAccess = MutexCreate();
41 m_dwReceiverBufferSize = 4194304; // 4MB
42 m_hSocket = -1;
43 m_pItemList = NULL;
44
45 m_ppEventTemplates = NULL;
46 m_dwNumTemplates = 0;
47 m_mutexEventAccess = MutexCreate();
48
49 m_dwNumUsers = 0;
50 m_pUserList = NULL;
51
52 #ifdef _WIN32
53 m_condSyncOp = CreateEvent(NULL, FALSE, FALSE, NULL);
54 #else
55 pthread_mutex_init(&m_mutexSyncOp, NULL);
56 pthread_cond_init(&m_condSyncOp, NULL);
57 #endif
58 }
59
60
61 //
62 // Session class destructor
63 //
64
65 NXCL_Session::~NXCL_Session()
66 {
67 Disconnect();
68 MutexDestroy(m_mutexIndexAccess);
69
70 MutexLock(m_mutexEventAccess, INFINITE);
71 MutexUnlock(m_mutexEventAccess);
72 MutexDestroy(m_mutexEventAccess);
73
74 #ifdef _WIN32
75 CloseHandle(m_condSyncOp);
76 #else
77 pthread_mutex_destroy(&m_mutexSyncOp);
78 pthread_cond_destroy(&m_condSyncOp);
79 #endif
80 }
81
82
83 //
84 // Disconnect session
85 //
86
87 void NXCL_Session::Disconnect(void)
88 {
89 // Close socket
90 shutdown(m_hSocket, SHUT_RDWR);
91 closesocket(m_hSocket);
92 m_hSocket = -1;
93
94 // Clear message wait queue
95 m_msgWaitQueue.Clear();
96
97 // Cleanup
98 DestroyAllObjects();
99 DestroyEventDB();
100 DestroyUserDB();
101 }
102
103
104 //
105 // Destroy all objects
106 //
107
108 void NXCL_Session::DestroyAllObjects(void)
109 {
110 DWORD i;
111
112 MutexLock(m_mutexIndexAccess, INFINITE);
113 for(i = 0; i < m_dwNumObjects; i++)
114 DestroyObject(m_pIndexById[i].pObject);
115 m_dwNumObjects = 0;
116 safe_free(m_pIndexById);
117 m_pIndexById = NULL;
118 MutexUnlock(m_mutexIndexAccess);
119 }
120
121
122 //
123 // Wait for specific message
124 //
125
126 CSCPMessage *NXCL_Session::WaitForMessage(WORD wCode, DWORD dwId, DWORD dwTimeOut)
127 {
128 return m_msgWaitQueue.WaitForMessage(wCode, dwId,
129 dwTimeOut == 0 ? m_dwCommandTimeout : dwTimeOut);
130 }
131
132
133 //
134 // Wait for specific raw message
135 //
136
137 CSCP_MESSAGE *NXCL_Session::WaitForRawMessage(WORD wCode, DWORD dwId, DWORD dwTimeOut)
138 {
139 return m_msgWaitQueue.WaitForRawMessage(wCode, dwId,
140 dwTimeOut == 0 ? m_dwCommandTimeout : dwTimeOut);
141 }
142
143
144 //
145 // Wait for request completion notification and extract result code
146 // from recived message
147 //
148
149 DWORD NXCL_Session::WaitForRCC(DWORD dwRqId)
150 {
151 CSCPMessage *pResponce;
152 DWORD dwRetCode;
153
154 pResponce = WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId, m_dwCommandTimeout);
155 if (pResponce != NULL)
156 {
157 dwRetCode = pResponce->GetVariableLong(VID_RCC);
158 delete pResponce;
159 }
160 else
161 {
162 dwRetCode = RCC_TIMEOUT;
163 }
164 return dwRetCode;
165 }
166
167
168 //
169 // Send CSCP message
170 //
171
172 BOOL NXCL_Session::SendMsg(CSCPMessage *pMsg)
173 {
174 CSCP_MESSAGE *pRawMsg;
175 BOOL bResult;
176 TCHAR szBuffer[128];
177
178 DebugPrintf(_T("SendMsg(\"%s\"), id:%ld)"), CSCPMessageCodeName(pMsg->GetCode(), szBuffer), pMsg->GetId());
179 pRawMsg = pMsg->CreateMessage();
180 bResult = (send(m_hSocket, (char *)pRawMsg, ntohl(pRawMsg->dwSize), 0) == (int)ntohl(pRawMsg->dwSize));
181 free(pRawMsg);
182 return bResult;
183 }
184
185
186 //
187 // Wait for synchronization operation completion
188 //
189
190 DWORD NXCL_Session::WaitForSync(DWORD dwTimeOut)
191 {
192 #ifdef _WIN32
193 DWORD dwRetCode;
194
195 dwRetCode = WaitForSingleObject(m_condSyncOp, dwTimeOut);
196 return (dwRetCode == WAIT_TIMEOUT) ? RCC_TIMEOUT : m_dwSyncExitCode;
197 #else
198 int iRetCode;
199 DWORD dwResult;
200
201 pthread_mutex_lock(&m_mutexSyncOp);
202 if (!(m_dwFlags & NXC_SF_SYNC_FINISHED))
203 {
204 if (dwTimeOut != INFINITE)
205 {
206 #if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP
207 struct timespec timeout;
208
209 timeout.tv_sec = dwTimeOut / 1000;
210 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
211 iRetCode = pthread_cond_reltimedwait_np(&m_condSyncOp, &m_mutexSyncOp, &timeout);
212 #else
213 struct timeval now;
214 struct timespec timeout;
215
216 gettimeofday(&now, NULL);
217 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
218 timeout.tv_nsec = ( now.tv_usec + ( dwTimeOut % 1000 ) * 1000) * 1000;
219 iRetCode = pthread_cond_timedwait(&m_condSyncOp, &m_mutexSyncOp, &timeout);
220 #endif
221 }
222 else
223 {
224 iRetCode = pthread_cond_wait(&m_condSyncOp, &m_mutexSyncOp);
225 }
226 dwResult = (iRetCode == 0) ? m_dwSyncExitCode : RCC_TIMEOUT;
227 }
228 else
229 {
230 dwResult = m_dwSyncExitCode;
231 }
232 pthread_mutex_unlock(&m_mutexSyncOp);
233 return dwResult;
234 #endif
235 }
236
237
238 //
239 // Prepare for synchronization operation
240 //
241
242 void NXCL_Session::PrepareForSync(void)
243 {
244 m_dwSyncExitCode = RCC_SYSTEM_FAILURE;
245 #ifdef _WIN32
246 ResetEvent(m_condSyncOp);
247 #else
248 m_dwFlags &= ~NXC_SF_SYNC_FINISHED;
249 #endif
250 }
251
252
253 //
254 // Complete synchronization operation
255 //
256
257 void NXCL_Session::CompleteSync(DWORD dwRetCode)
258 {
259 #ifdef _WIN32
260 m_dwSyncExitCode = dwRetCode;
261 SetEvent(m_condSyncOp);
262 #else
263 pthread_mutex_lock(&m_mutexSyncOp);
264 m_dwSyncExitCode = dwRetCode;
265 m_dwFlags |= NXC_SF_SYNC_FINISHED;
266 pthread_cond_signal(&m_condSyncOp);
267 pthread_mutex_unlock(&m_mutexSyncOp);
268 #endif
269 }
270
271
272 //
273 // Process DCIs coming from server
274 //
275
276 void NXCL_Session::ProcessDCI(CSCPMessage *pMsg)
277 {
278 switch(pMsg->GetCode())
279 {
280 case CMD_NODE_DCI_LIST_END:
281 CompleteSync(RCC_SUCCESS);
282 break;
283 case CMD_NODE_DCI:
284 if (m_pItemList != NULL)
285 {
286 DWORD i, j, dwId;
287 DCI_THRESHOLD dct;
288
289 i = m_pItemList->dwNumItems;
290 m_pItemList->dwNumItems++;
291 m_pItemList->pItems = (NXC_DCI *)realloc(m_pItemList->pItems,
292 sizeof(NXC_DCI) * m_pItemList->dwNumItems);
293 m_pItemList->pItems[i].dwId = pMsg->GetVariableLong(VID_DCI_ID);
294 m_pItemList->pItems[i].iDataType = (BYTE)pMsg->GetVariableShort(VID_DCI_DATA_TYPE);
295 m_pItemList->pItems[i].iPollingInterval = (int)pMsg->GetVariableLong(VID_POLLING_INTERVAL);
296 m_pItemList->pItems[i].iRetentionTime = (int)pMsg->GetVariableLong(VID_RETENTION_TIME);
297 m_pItemList->pItems[i].iSource = (BYTE)pMsg->GetVariableShort(VID_DCI_SOURCE_TYPE);
298 m_pItemList->pItems[i].iStatus = (BYTE)pMsg->GetVariableShort(VID_DCI_STATUS);
299 m_pItemList->pItems[i].iDeltaCalculation = (BYTE)pMsg->GetVariableShort(VID_DCI_DELTA_CALCULATION);
300 m_pItemList->pItems[i].pszFormula = pMsg->GetVariableStr(VID_DCI_FORMULA);
301 pMsg->GetVariableStr(VID_NAME, m_pItemList->pItems[i].szName, MAX_ITEM_NAME);
302 pMsg->GetVariableStr(VID_DESCRIPTION, m_pItemList->pItems[i].szDescription,
303 MAX_DB_STRING);
304 pMsg->GetVariableStr(VID_INSTANCE, m_pItemList->pItems[i].szInstance,
305 MAX_DB_STRING);
306 m_pItemList->pItems[i].dwNumThresholds = pMsg->GetVariableLong(VID_NUM_THRESHOLDS);
307 m_pItemList->pItems[i].pThresholdList =
308 (NXC_DCI_THRESHOLD *)malloc(sizeof(NXC_DCI_THRESHOLD) * m_pItemList->pItems[i].dwNumThresholds);
309 for(j = 0, dwId = VID_DCI_THRESHOLD_BASE; j < m_pItemList->pItems[i].dwNumThresholds; j++, dwId++)
310 {
311 pMsg->GetVariableBinary(dwId, (BYTE *)&dct, sizeof(DCI_THRESHOLD));
312 m_pItemList->pItems[i].pThresholdList[j].dwId = ntohl(dct.dwId);
313 m_pItemList->pItems[i].pThresholdList[j].dwEvent = ntohl(dct.dwEvent);
314 m_pItemList->pItems[i].pThresholdList[j].dwArg1 = ntohl(dct.dwArg1);
315 m_pItemList->pItems[i].pThresholdList[j].dwArg2 = ntohl(dct.dwArg2);
316 m_pItemList->pItems[i].pThresholdList[j].wFunction = ntohs(dct.wFunction);
317 m_pItemList->pItems[i].pThresholdList[j].wOperation = ntohs(dct.wOperation);
318 switch(m_pItemList->pItems[i].iDataType)
319 {
320 case DCI_DT_INT:
321 case DCI_DT_UINT:
322 m_pItemList->pItems[i].pThresholdList[j].value.dwInt32 = ntohl(dct.value.dwInt32);
323 break;
324 case DCI_DT_INT64:
325 case DCI_DT_UINT64:
326 m_pItemList->pItems[i].pThresholdList[j].value.qwInt64 = ntohq(dct.value.qwInt64);
327 break;
328 case DCI_DT_FLOAT:
329 m_pItemList->pItems[i].pThresholdList[j].value.dFloat = ntohd(dct.value.dFloat);
330 break;
331 case DCI_DT_STRING:
332 _tcscpy(m_pItemList->pItems[i].pThresholdList[j].value.szString, dct.value.szString);
333 break;
334 default:
335 break;
336 }
337 }
338 }
339 break;
340 default:
341 break;
342 }
343 }
344
345
346 //
347 // Load data collection items list for specified node
348 // This function is NOT REENTRANT
349 //
350
351 DWORD NXCL_Session::OpenNodeDCIList(DWORD dwNodeId, NXC_DCI_LIST **ppItemList)
352 {
353 CSCPMessage msg;
354 DWORD dwRetCode, dwRqId;
355
356 dwRqId = CreateRqId();
357 PrepareForSync();
358
359 m_pItemList = (NXC_DCI_LIST *)malloc(sizeof(NXC_DCI_LIST));
360 m_pItemList->dwNodeId = dwNodeId;
361 m_pItemList->dwNumItems = 0;
362 m_pItemList->pItems = NULL;
363
364 msg.SetCode(CMD_GET_NODE_DCI_LIST);
365 msg.SetId(dwRqId);
366 msg.SetVariable(VID_OBJECT_ID, dwNodeId);
367 SendMsg(&msg);
368
369 dwRetCode = WaitForRCC(dwRqId);
370
371 if (dwRetCode == RCC_SUCCESS)
372 {
373 // Wait for DCI list end or for disconnection
374 dwRetCode = WaitForSync(INFINITE);
375 if (dwRetCode == RCC_SUCCESS)
376 {
377 *ppItemList = m_pItemList;
378 }
379 else
380 {
381 free(m_pItemList);
382 }
383 }
384 else
385 {
386 free(m_pItemList);
387 }
388
389 m_pItemList = NULL;
390 return dwRetCode;
391 }
392
393
394 //
395 // Load event configuration database
396 //
397
398 DWORD NXCL_Session::LoadEventDB(void)
399 {
400 CSCPMessage msg;
401 DWORD dwRetCode, dwRqId;
402
403 dwRqId = CreateRqId();
404 PrepareForSync();
405
406 DestroyEventDB();
407 MutexLock(m_mutexEventAccess, INFINITE);
408
409 msg.SetCode(CMD_LOAD_EVENT_DB);
410 msg.SetId(dwRqId);
411 SendMsg(&msg);
412
413 dwRetCode = WaitForRCC(dwRqId);
414
415 /* TODO: this probably should be recoded as loop with calls to WaitForMessage() */
416 if (dwRetCode == RCC_SUCCESS)
417 dwRetCode = WaitForSync(INFINITE);
418
419 MutexUnlock(m_mutexEventAccess);
420 return dwRetCode;
421 }
422
423
424 //
425 // Destroy event template database
426 //
427
428 void NXCL_Session::DestroyEventDB(void)
429 {
430 DWORD i;
431
432 for(i = 0; i < m_dwNumTemplates; i++)
433 {
434 safe_free(m_ppEventTemplates[i]->pszDescription);
435 safe_free(m_ppEventTemplates[i]->pszMessage);
436 free(m_ppEventTemplates[i]);
437 }
438 safe_free(m_ppEventTemplates);
439 m_dwNumTemplates = 0;
440 m_ppEventTemplates = NULL;
441 }
442
443
444 //
445 // Delete record from list
446 //
447
448 void NXCL_Session::DeleteEDBRecord(DWORD dwEventCode)
449 {
450 DWORD i;
451
452 MutexLock(m_mutexEventAccess, INFINITE);
453 for(i = 0; i < m_dwNumTemplates; i++)
454 if (m_ppEventTemplates[i]->dwCode == dwEventCode)
455 {
456 m_dwNumTemplates--;
457 safe_free(m_ppEventTemplates[i]->pszDescription);
458 safe_free(m_ppEventTemplates[i]->pszMessage);
459 free(m_ppEventTemplates[i]);
460 memmove(&m_ppEventTemplates[i], m_ppEventTemplates[i + 1],
461 sizeof(NXC_EVENT_TEMPLATE *) * (m_dwNumTemplates - i));
462 break;
463 }
464 MutexUnlock(m_mutexEventAccess);
465 }
466
467
468 //
469 // Add template to list
470 //
471
472 void NXCL_Session::AddEventTemplate(NXC_EVENT_TEMPLATE *pEventTemplate, BOOL bLock)
473 {
474 if (bLock)
475 MutexLock(m_mutexEventAccess, INFINITE);
476 m_ppEventTemplates = (NXC_EVENT_TEMPLATE **)realloc(m_ppEventTemplates,
477 sizeof(NXC_EVENT_TEMPLATE *) * (m_dwNumTemplates + 1));
478 m_ppEventTemplates[m_dwNumTemplates] = pEventTemplate;
479 m_dwNumTemplates++;
480 if (bLock)
481 MutexUnlock(m_mutexEventAccess);
482 }
483
484
485 //
486 // Get pointer to event templates list
487 //
488
489 BOOL NXCL_Session::GetEventDB(NXC_EVENT_TEMPLATE ***pppTemplateList, DWORD *pdwNumRecords)
490 {
491 *pppTemplateList = m_ppEventTemplates;
492 *pdwNumRecords = m_dwNumTemplates;
493 return TRUE;
494 }
495
496
497 //
498 // Resolve event id to name
499 //
500
501 const TCHAR *NXCL_Session::GetEventName(DWORD dwId)
502 {
503 DWORD i;
504
505 MutexLock(m_mutexEventAccess, INFINITE);
506 for(i = 0; i < m_dwNumTemplates; i++)
507 if (m_ppEventTemplates[i]->dwCode == dwId)
508 {
509 MutexUnlock(m_mutexEventAccess);
510 return m_ppEventTemplates[i]->szName;
511 }
512 MutexUnlock(m_mutexEventAccess);
513 return _T("<unknown>");
514 }
515
516
517 //
518 // Resolve event id to name using application-provided buffer
519 //
520
521 BOOL NXCL_Session::GetEventNameEx(DWORD dwId, TCHAR *pszBuffer, DWORD dwBufSize)
522 {
523 DWORD i;
524
525 MutexLock(m_mutexEventAccess, INFINITE);
526 for(i = 0; i < m_dwNumTemplates; i++)
527 if (m_ppEventTemplates[i]->dwCode == dwId)
528 {
529 _tcsncpy(pszBuffer, m_ppEventTemplates[i]->szName, dwBufSize);
530 MutexUnlock(m_mutexEventAccess);
531 return TRUE;
532 }
533 MutexUnlock(m_mutexEventAccess);
534 *pszBuffer = 0;
535 return FALSE;
536 }
537
538
539 //
540 // Get severity for given event id. Will return -1 for unknown id.
541 //
542
543 int NXCL_Session::GetEventSeverity(DWORD dwId)
544 {
545 DWORD i;
546
547 MutexLock(m_mutexEventAccess, INFINITE);
548 for(i = 0; i < m_dwNumTemplates; i++)
549 if (m_ppEventTemplates[i]->dwCode == dwId)
550 {
551 MutexUnlock(m_mutexEventAccess);
552 return (int)(m_ppEventTemplates[i]->dwSeverity);
553 }
554 MutexUnlock(m_mutexEventAccess);
555 return -1;
556 }
557
558
559 //
560 // Get text of event template with given ID.
561 // If there are no template with such ID, empty string will be returned.
562 //
563
564 BOOL NXCL_Session::GetEventText(DWORD dwId, TCHAR *pszBuffer, DWORD dwBufSize)
565 {
566 DWORD i;
567
568 MutexLock(m_mutexEventAccess, INFINITE);
569 for(i = 0; i < m_dwNumTemplates; i++)
570 if (m_ppEventTemplates[i]->dwCode == dwId)
571 {
572 _tcsncpy(pszBuffer, m_ppEventTemplates[i]->pszMessage, dwBufSize);
573 MutexUnlock(m_mutexEventAccess);
574 return TRUE;
575 }
576 MutexUnlock(m_mutexEventAccess);
577 *pszBuffer = 0;
578 return FALSE;
579 }
580
581
582 //
583 // Destroy user database
584 //
585
586 void NXCL_Session::DestroyUserDB(void)
587 {
588 DWORD i;
589
590 for(i = 0; i < m_dwNumUsers; i++)
591 safe_free(m_pUserList[i].pdwMemberList);
592 safe_free(m_pUserList);
593 m_pUserList = NULL;
594 m_dwNumUsers = 0;
595 m_dwFlags &= ~NXC_SF_USERDB_LOADED;
596 }
597
598
599 //
600 // Process user record from network
601 //
602
603 void NXCL_Session::ProcessUserDBRecord(CSCPMessage *pMsg)
604 {
605 switch(pMsg->GetCode())
606 {
607 case CMD_USER_DB_EOF:
608 CompleteSync(RCC_SUCCESS);
609 break;
610 case CMD_USER_DATA:
611 case CMD_GROUP_DATA:
612 m_pUserList = (NXC_USER *)realloc(m_pUserList, sizeof(NXC_USER) * (m_dwNumUsers + 1));
613 memset(&m_pUserList[m_dwNumUsers], 0, sizeof(NXC_USER));
614 UpdateUserFromMessage(pMsg, &m_pUserList[m_dwNumUsers]);
615 m_dwNumUsers++;
616 break;
617 default:
618 break;
619 }
620 }
621
622
623 //
624 // Process user database update
625 //
626
627 void NXCL_Session::ProcessUserDBUpdate(CSCPMessage *pMsg)
628 {
629 int iCode;
630 DWORD dwUserId;
631 NXC_USER *pUser;
632
633 iCode = pMsg->GetVariableShort(VID_UPDATE_TYPE);
634 dwUserId = pMsg->GetVariableLong(VID_USER_ID);
635 pUser = FindUserById(dwUserId);
636
637 switch(iCode)
638 {
639 case USER_DB_CREATE:
640 if (pUser == NULL)
641 {
642 // No user with this id, create one
643 m_pUserList = (NXC_USER *)realloc(m_pUserList, sizeof(NXC_USER) * (m_dwNumUsers + 1));
644 memset(&m_pUserList[m_dwNumUsers], 0, sizeof(NXC_USER));
645
646 // Process common fields
647 m_pUserList[m_dwNumUsers].dwId = dwUserId;
648 pMsg->GetVariableStr(VID_USER_NAME, m_pUserList[m_dwNumUsers].szName, MAX_USER_NAME);
649 pUser = &m_pUserList[m_dwNumUsers];
650 m_dwNumUsers++;
651 }
652 break;
653 case USER_DB_MODIFY:
654 if (pUser == NULL)
655 {
656 // No user with this id, create one
657 m_pUserList = (NXC_USER *)realloc(m_pUserList, sizeof(NXC_USER) * (m_dwNumUsers + 1));
658 memset(&m_pUserList[m_dwNumUsers], 0, sizeof(NXC_USER));
659 pUser = &m_pUserList[m_dwNumUsers];
660 m_dwNumUsers++;
661 }
662 UpdateUserFromMessage(pMsg, pUser);
663 break;
664 case USER_DB_DELETE:
665 if (pUser != NULL)
666 pUser->wFlags |= UF_DELETED;
667 break;
668 default:
669 break;
670 }
671
672 if (pUser != NULL)
673 CallEventHandler(NXC_EVENT_USER_DB_CHANGED, iCode, pUser);
674 }
675
676
677 //
678 // Find user in database by ID
679 //
680
681 NXC_USER *NXCL_Session::FindUserById(DWORD dwId)
682 {
683 DWORD i;
684 NXC_USER *pUser = NULL;
685
686 if (m_dwFlags & NXC_SF_USERDB_LOADED)
687 {
688 for(i = 0; i < m_dwNumUsers; i++)
689 if (m_pUserList[i].dwId == dwId)
690 {
691 pUser = &m_pUserList[i];
692 break;
693 }
694 }
695
696 return pUser;
697 }
698
699
700 //
701 // Get pointer to user list and number of users
702 //
703
704 BOOL NXCL_Session::GetUserDB(NXC_USER **ppUserList, DWORD *pdwNumUsers)
705 {
706 if (!(m_dwFlags & NXC_SF_USERDB_LOADED))
707 return FALSE;
708
709 *ppUserList = m_pUserList;
710 *pdwNumUsers = m_dwNumUsers;
711 return TRUE;
712 }
713
714
715 //
716 // Load user database
717 // This function is NOT REENTRANT
718 //
719
720 DWORD NXCL_Session::LoadUserDB(void)
721 {
722 CSCPMessage msg;
723 DWORD dwRetCode, dwRqId;
724
725 dwRqId = CreateRqId();
726 PrepareForSync();
727 DestroyUserDB();
728
729 msg.SetCode(CMD_LOAD_USER_DB);
730 msg.SetId(dwRqId);
731 SendMsg(&msg);
732
733 dwRetCode = WaitForRCC(dwRqId);
734
735 if (dwRetCode == RCC_SUCCESS)
736 {
737 dwRetCode = WaitForSync(INFINITE);
738 if (dwRetCode == RCC_SUCCESS)
739 m_dwFlags |= NXC_SF_USERDB_LOADED;
740 }
741
742 return dwRetCode;
743 }