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