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