fixed compiler warnings; minor refactoring
[public/netxms.git] / src / server / core / mdsession.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
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: mdsession.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 #ifdef _WIN32
26 #include <psapi.h>
27 #endif
28
29 // WARNING! this hack works only for d2i_X509(); be carefull when adding new code
30 #ifdef OPENSSL_CONST
31 # undef OPENSSL_CONST
32 #endif
33 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
34 # define OPENSSL_CONST const
35 #else
36 # define OPENSSL_CONST
37 #endif
38
39 /**
40 * Constants
41 */
42 #define MAX_MSG_SIZE 65536
43
44 /**
45 * Externals
46 */
47 void UnregisterMobileDeviceSession(int id);
48
49 /**
50 * Client communication read thread starter
51 */
52 THREAD_RESULT THREAD_CALL MobileDeviceSession::readThreadStarter(void *pArg)
53 {
54 ((MobileDeviceSession *)pArg)->readThread();
55
56 // When MobileDeviceSession::readThread exits, all other session
57 // threads are already stopped, so we can safely destroy
58 // session object
59 UnregisterMobileDeviceSession(((MobileDeviceSession *)pArg)->getId());
60 delete (MobileDeviceSession *)pArg;
61 return THREAD_OK;
62 }
63
64 /**
65 * Client communication write thread starter
66 */
67 THREAD_RESULT THREAD_CALL MobileDeviceSession::writeThreadStarter(void *pArg)
68 {
69 ((MobileDeviceSession *)pArg)->writeThread();
70 return THREAD_OK;
71 }
72
73 /**
74 * Received message processing thread starter
75 */
76 THREAD_RESULT THREAD_CALL MobileDeviceSession::processingThreadStarter(void *pArg)
77 {
78 ((MobileDeviceSession *)pArg)->processingThread();
79 return THREAD_OK;
80 }
81
82 /**
83 * Mobile device session class constructor
84 */
85 MobileDeviceSession::MobileDeviceSession(SOCKET hSocket, const InetAddress& addr)
86 {
87 m_pSendQueue = new Queue;
88 m_pMessageQueue = new Queue;
89 m_hSocket = hSocket;
90 m_id = -1;
91 m_state = SESSION_STATE_INIT;
92 m_pMsgBuffer = (NXCP_BUFFER *)malloc(sizeof(NXCP_BUFFER));
93 m_pCtx = NULL;
94 m_hWriteThread = INVALID_THREAD_HANDLE;
95 m_hProcessingThread = INVALID_THREAD_HANDLE;
96 m_mutexSocketWrite = MutexCreate();
97 m_clientAddr = addr;
98 m_clientAddr.toString(m_szHostName);
99 _tcscpy(m_szUserName, _T("<not logged in>"));
100 _tcscpy(m_szClientInfo, _T("n/a"));
101 m_dwUserId = INVALID_INDEX;
102 m_deviceObjectId = 0;
103 m_dwEncryptionRqId = 0;
104 m_condEncryptionSetup = INVALID_CONDITION_HANDLE;
105 m_dwRefCount = 0;
106 m_isAuthenticated = false;
107 m_wCurrentCmd = 0;
108 m_dwEncryptionResult = 0;
109 }
110
111 /**
112 * Destructor
113 */
114 MobileDeviceSession::~MobileDeviceSession()
115 {
116 if (m_hSocket != -1)
117 closesocket(m_hSocket);
118 delete m_pSendQueue;
119 delete m_pMessageQueue;
120 free(m_pMsgBuffer);
121 MutexDestroy(m_mutexSocketWrite);
122 if (m_pCtx != NULL)
123 m_pCtx->decRefCount();
124 if (m_condEncryptionSetup != INVALID_CONDITION_HANDLE)
125 ConditionDestroy(m_condEncryptionSetup);
126 }
127
128 /**
129 * Start all threads
130 */
131 void MobileDeviceSession::run()
132 {
133 m_hWriteThread = ThreadCreateEx(writeThreadStarter, 0, this);
134 m_hProcessingThread = ThreadCreateEx(processingThreadStarter, 0, this);
135 ThreadCreate(readThreadStarter, 0, this);
136 }
137
138 /**
139 * Print debug information
140 */
141 void MobileDeviceSession::debugPrintf(int level, const TCHAR *format, ...)
142 {
143 if (level <= nxlog_get_debug_level())
144 {
145 va_list args;
146 TCHAR buffer[4096];
147
148 va_start(args, format);
149 _vsntprintf(buffer, 4096, format, args);
150 va_end(args);
151 DbgPrintf(level, _T("[MDSN-%d] %s"), m_id, buffer);
152 }
153 }
154
155 /**
156 * Read thread
157 */
158 void MobileDeviceSession::readThread()
159 {
160 SocketMessageReceiver receiver(m_hSocket, 4096, MAX_MSG_SIZE);
161 while(1)
162 {
163 MessageReceiverResult result;
164 NXCPMessage *msg = receiver.readMessage(900000, &result);
165
166 // Check for decryption error
167 if (result == MSGRECV_DECRYPTION_FAILURE)
168 {
169 debugPrintf(4, _T("Unable to decrypt received message"));
170 continue;
171 }
172
173 // Receive error
174 if (msg == NULL)
175 {
176 debugPrintf(5, _T("readThread: message receiving error (%s)"), AbstractMessageReceiver::resultToText(result));
177 break;
178 }
179
180 if (nxlog_get_debug_level() >= 8)
181 {
182 String msgDump = NXCPMessage::dump(receiver.getRawMessageBuffer(), NXCP_VERSION);
183 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
184 }
185
186 TCHAR szBuffer[256];
187 if ((msg->getCode() == CMD_SESSION_KEY) && (msg->getId() == m_dwEncryptionRqId))
188 {
189 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
190 m_dwEncryptionResult = SetupEncryptionContext(msg, &m_pCtx, NULL, g_pServerKey, NXCP_VERSION);
191 receiver.setEncryptionContext(m_pCtx);
192 ConditionSet(m_condEncryptionSetup);
193 m_dwEncryptionRqId = 0;
194 delete msg;
195 }
196 else if (msg->getCode() == CMD_KEEPALIVE)
197 {
198 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
199 respondToKeepalive(msg->getId());
200 delete msg;
201 }
202 else
203 {
204 m_pMessageQueue->put(msg);
205 }
206 }
207
208 // Notify other threads to exit
209 NXCP_MESSAGE *rawMsg;
210 while((rawMsg = (NXCP_MESSAGE *)m_pSendQueue->get()) != NULL)
211 free(rawMsg);
212 m_pSendQueue->put(INVALID_POINTER_VALUE);
213
214 NXCPMessage *msg;
215 while((msg = (NXCPMessage *)m_pMessageQueue->get()) != NULL)
216 delete msg;
217 m_pMessageQueue->put(INVALID_POINTER_VALUE);
218
219 // Wait for other threads to finish
220 ThreadJoin(m_hWriteThread);
221 ThreadJoin(m_hProcessingThread);
222
223 // Waiting while reference count becomes 0
224 if (m_dwRefCount > 0)
225 {
226 debugPrintf(3, _T("Waiting for pending requests..."));
227 do
228 {
229 ThreadSleep(1);
230 } while(m_dwRefCount > 0);
231 }
232
233 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_szHostName, m_id, 0, _T("Mobile device logged out (client: %s)"), m_szClientInfo);
234 debugPrintf(3, _T("Session closed"));
235 }
236
237 /**
238 * Network write thread
239 */
240 void MobileDeviceSession::writeThread()
241 {
242 NXCP_MESSAGE *pRawMsg;
243 NXCP_ENCRYPTED_MESSAGE *pEnMsg;
244 TCHAR szBuffer[128];
245 BOOL bResult;
246
247 while(1)
248 {
249 pRawMsg = (NXCP_MESSAGE *)m_pSendQueue->getOrBlock();
250 if (pRawMsg == INVALID_POINTER_VALUE) // Session termination indicator
251 break;
252
253 if (ntohs(pRawMsg->code) != CMD_ADM_MESSAGE)
254 debugPrintf(6, _T("Sending message %s"), NXCPMessageCodeName(ntohs(pRawMsg->code), szBuffer));
255
256 if (m_pCtx != NULL)
257 {
258 pEnMsg = m_pCtx->encryptMessage(pRawMsg);
259 if (pEnMsg != NULL)
260 {
261 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->size));
262 free(pEnMsg);
263 }
264 else
265 {
266 bResult = FALSE;
267 }
268 }
269 else
270 {
271 bResult = (SendEx(m_hSocket, (const char *)pRawMsg, ntohl(pRawMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->size));
272 }
273 free(pRawMsg);
274
275 if (!bResult)
276 {
277 closesocket(m_hSocket);
278 m_hSocket = -1;
279 break;
280 }
281 }
282 }
283
284 /**
285 * Message processing thread
286 */
287 void MobileDeviceSession::processingThread()
288 {
289 NXCPMessage *msg;
290 TCHAR szBuffer[128];
291 UINT32 i;
292 int status;
293
294 while(1)
295 {
296 msg = (NXCPMessage *)m_pMessageQueue->getOrBlock();
297 if (msg == INVALID_POINTER_VALUE) // Session termination indicator
298 break;
299
300 m_wCurrentCmd = msg->getCode();
301 debugPrintf(6, _T("Received message %s"), NXCPMessageCodeName(m_wCurrentCmd, szBuffer));
302 if (!m_isAuthenticated &&
303 (m_wCurrentCmd != CMD_LOGIN) &&
304 (m_wCurrentCmd != CMD_GET_SERVER_INFO) &&
305 (m_wCurrentCmd != CMD_REQUEST_ENCRYPTION))
306 {
307 delete msg;
308 continue;
309 }
310
311 m_state = SESSION_STATE_PROCESSING;
312 switch(m_wCurrentCmd)
313 {
314 case CMD_GET_SERVER_INFO:
315 sendServerInfo(msg->getId());
316 break;
317 case CMD_LOGIN:
318 login(msg);
319 break;
320 case CMD_REQUEST_ENCRYPTION:
321 setupEncryption(msg);
322 break;
323 case CMD_REPORT_DEVICE_INFO:
324 updateDeviceInfo(msg);
325 break;
326 case CMD_REPORT_DEVICE_STATUS:
327 updateDeviceStatus(msg);
328 break;
329 case CMD_PUSH_DCI_DATA:
330 pushData(msg);
331 break;
332 default:
333 // Pass message to loaded modules
334 for(i = 0; i < g_dwNumModules; i++)
335 {
336 if (g_pModuleList[i].pfMobileDeviceCommandHandler != NULL)
337 {
338 status = g_pModuleList[i].pfMobileDeviceCommandHandler(m_wCurrentCmd, msg, this);
339 if (status != NXMOD_COMMAND_IGNORED)
340 {
341 if (status == NXMOD_COMMAND_ACCEPTED_ASYNC)
342 {
343 msg = NULL; // Prevent deletion
344 }
345 break; // Message was processed by the module
346 }
347 }
348 }
349 if (i == g_dwNumModules)
350 {
351 NXCPMessage response;
352
353 response.setId(msg->getId());
354 response.setCode(CMD_REQUEST_COMPLETED);
355 response.setField(VID_RCC, RCC_NOT_IMPLEMENTED);
356 sendMessage(&response);
357 }
358 break;
359 }
360 delete msg;
361 m_state = m_isAuthenticated ? SESSION_STATE_IDLE : SESSION_STATE_INIT;
362 }
363 }
364
365 /**
366 * Respond to client's keepalive message
367 */
368 void MobileDeviceSession::respondToKeepalive(UINT32 dwRqId)
369 {
370 NXCPMessage msg;
371
372 msg.setCode(CMD_REQUEST_COMPLETED);
373 msg.setId(dwRqId);
374 msg.setField(VID_RCC, RCC_SUCCESS);
375 sendMessage(&msg);
376 }
377
378 /**
379 * Send message to client
380 */
381 void MobileDeviceSession::sendMessage(NXCPMessage *msg)
382 {
383 TCHAR szBuffer[128];
384 BOOL bResult;
385
386 debugPrintf(6, _T("Sending message %s"), NXCPMessageCodeName(msg->getCode(), szBuffer));
387 NXCP_MESSAGE *pRawMsg = msg->serialize();
388 if (nxlog_get_debug_level() >= 8)
389 {
390 String msgDump = NXCPMessage::dump(pRawMsg, NXCP_VERSION);
391 debugPrintf(8, _T("Message dump:\n%s"), (const TCHAR *)msgDump);
392 }
393 if (m_pCtx != NULL)
394 {
395 NXCP_ENCRYPTED_MESSAGE *pEnMsg = m_pCtx->encryptMessage(pRawMsg);
396 if (pEnMsg != NULL)
397 {
398 bResult = (SendEx(m_hSocket, (char *)pEnMsg, ntohl(pEnMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(pEnMsg->size));
399 free(pEnMsg);
400 }
401 else
402 {
403 bResult = FALSE;
404 }
405 }
406 else
407 {
408 bResult = (SendEx(m_hSocket, (const char *)pRawMsg, ntohl(pRawMsg->size), 0, m_mutexSocketWrite) == (int)ntohl(pRawMsg->size));
409 }
410 free(pRawMsg);
411
412 if (!bResult)
413 {
414 closesocket(m_hSocket);
415 m_hSocket = -1;
416 }
417 }
418
419 /**
420 * Send server information to client
421 */
422 void MobileDeviceSession::sendServerInfo(UINT32 dwRqId)
423 {
424 NXCPMessage msg;
425
426 // Prepare response message
427 msg.setCode(CMD_REQUEST_COMPLETED);
428 msg.setId(dwRqId);
429
430 // Generate challenge for certificate authentication
431 #ifdef _WITH_ENCRYPTION
432 RAND_bytes(m_challenge, CLIENT_CHALLENGE_SIZE);
433 #else
434 memset(m_challenge, 0, CLIENT_CHALLENGE_SIZE);
435 #endif
436
437 // Fill message with server info
438 msg.setField(VID_RCC, RCC_SUCCESS);
439 msg.setField(VID_SERVER_VERSION, NETXMS_VERSION_STRING);
440 msg.setField(VID_SERVER_ID, g_serverId);
441 msg.setField(VID_PROTOCOL_VERSION, (UINT32)MOBILE_DEVICE_PROTOCOL_VERSION);
442 msg.setField(VID_CHALLENGE, m_challenge, CLIENT_CHALLENGE_SIZE);
443
444 // Send response
445 sendMessage(&msg);
446 }
447
448 /**
449 * Authenticate client
450 */
451 void MobileDeviceSession::login(NXCPMessage *pRequest)
452 {
453 NXCPMessage msg;
454 TCHAR szLogin[MAX_USER_NAME], szPassword[1024];
455 int nAuthType;
456 bool changePasswd = false, intruderLockout = false, closeOtherSessions = false;
457 UINT32 dwResult;
458 #ifdef _WITH_ENCRYPTION
459 X509 *pCert;
460 #endif
461
462 // Prepare response message
463 msg.setCode(CMD_LOGIN_RESP);
464 msg.setId(pRequest->getId());
465
466 // Get client info string
467 if (pRequest->isFieldExist(VID_CLIENT_INFO))
468 {
469 TCHAR szClientInfo[32], szOSInfo[32], szLibVersion[16];
470
471 pRequest->getFieldAsString(VID_CLIENT_INFO, szClientInfo, 32);
472 pRequest->getFieldAsString(VID_OS_INFO, szOSInfo, 32);
473 pRequest->getFieldAsString(VID_LIBNXCL_VERSION, szLibVersion, 16);
474 _sntprintf(m_szClientInfo, 96, _T("%s (%s; libnxcl %s)"),
475 szClientInfo, szOSInfo, szLibVersion);
476 }
477
478 if (!m_isAuthenticated)
479 {
480 pRequest->getFieldAsString(VID_LOGIN_NAME, szLogin, MAX_USER_NAME);
481 nAuthType = (int)pRequest->getFieldAsUInt16(VID_AUTH_TYPE);
482 UINT64 userRights;
483 UINT32 graceLogins;
484 switch(nAuthType)
485 {
486 case NETXMS_AUTH_TYPE_PASSWORD:
487 #ifdef UNICODE
488 pRequest->getFieldAsString(VID_PASSWORD, szPassword, 256);
489 #else
490 pRequest->getFieldAsUtf8String(VID_PASSWORD, szPassword, 1024);
491 #endif
492 dwResult = AuthenticateUser(szLogin, szPassword, 0, NULL, NULL, &m_dwUserId,
493 &userRights, &changePasswd, &intruderLockout,
494 &closeOtherSessions, false, &graceLogins);
495 break;
496 case NETXMS_AUTH_TYPE_CERTIFICATE:
497 #ifdef _WITH_ENCRYPTION
498 pCert = CertificateFromLoginMessage(pRequest);
499 if (pCert != NULL)
500 {
501 size_t sigLen;
502 const BYTE *signature = pRequest->getBinaryFieldPtr(VID_SIGNATURE, &sigLen);
503 if (signature != NULL)
504 {
505 dwResult = AuthenticateUser(szLogin, reinterpret_cast<const TCHAR *>(signature), sigLen,
506 pCert, m_challenge, &m_dwUserId, &userRights,
507 &changePasswd, &intruderLockout,
508 &closeOtherSessions, false, &graceLogins);
509 }
510 else
511 {
512 dwResult = RCC_INVALID_REQUEST;
513 }
514 X509_free(pCert);
515 }
516 else
517 {
518 dwResult = RCC_BAD_CERTIFICATE;
519 }
520 #else
521 dwResult = RCC_NOT_IMPLEMENTED;
522 #endif
523 break;
524 default:
525 dwResult = RCC_UNSUPPORTED_AUTH_TYPE;
526 break;
527 }
528
529 if (dwResult == RCC_SUCCESS)
530 {
531 if (userRights & SYSTEM_ACCESS_MOBILE_DEVICE_LOGIN)
532 {
533 TCHAR deviceId[MAX_OBJECT_NAME] = _T("");
534 pRequest->getFieldAsString(VID_DEVICE_ID, deviceId, MAX_OBJECT_NAME);
535 MobileDevice *md = FindMobileDeviceByDeviceID(deviceId);
536 if (md != NULL)
537 {
538 m_deviceObjectId = md->getId();
539 m_isAuthenticated = true;
540 _sntprintf(m_szUserName, MAX_SESSION_NAME, _T("%s@%s"), szLogin, m_szHostName);
541 msg.setField(VID_RCC, RCC_SUCCESS);
542 msg.setField(VID_USER_SYS_RIGHTS, userRights);
543 msg.setField(VID_USER_ID, m_dwUserId);
544 msg.setField(VID_CHANGE_PASSWD_FLAG, (WORD)changePasswd);
545 msg.setField(VID_DBCONN_STATUS, (WORD)((g_flags & AF_DB_CONNECTION_LOST) ? 0 : 1));
546 msg.setField(VID_ZONING_ENABLED, (WORD)((g_flags & AF_ENABLE_ZONING) ? 1 : 0));
547 debugPrintf(3, _T("User %s authenticated as mobile device"), m_szUserName);
548 WriteAuditLog(AUDIT_SECURITY, TRUE, m_dwUserId, m_szHostName, m_id, 0,
549 _T("Mobile device logged in as user \"%s\" (client info: %s)"), szLogin, m_szClientInfo);
550 }
551 else
552 {
553 debugPrintf(3, _T("Mobile device object with device ID \"%s\" not found"), deviceId);
554 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
555 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_szHostName, m_id, 0,
556 _T("Mobile device login as user \"%s\" failed - mobile device object not found (client info: %s)"),
557 szLogin, m_szClientInfo);
558 }
559 }
560 else
561 {
562 msg.setField(VID_RCC, RCC_ACCESS_DENIED);
563 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_szHostName, m_id, 0,
564 _T("Mobile device login as user \"%s\" failed - user does not have mobile device login rights (client info: %s)"),
565 szLogin, m_szClientInfo);
566 }
567 }
568 else
569 {
570 msg.setField(VID_RCC, dwResult);
571 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_szHostName, m_id, 0,
572 _T("Mobile device login as user \"%s\" failed with error code %d (client info: %s)"),
573 szLogin, dwResult, m_szClientInfo);
574 if (intruderLockout)
575 {
576 WriteAuditLog(AUDIT_SECURITY, FALSE, m_dwUserId, m_szHostName, m_id, 0,
577 _T("User account \"%s\" temporary disabled due to excess count of failed authentication attempts"), szLogin);
578 }
579 }
580 }
581 else
582 {
583 msg.setField(VID_RCC, RCC_OUT_OF_STATE_REQUEST);
584 }
585
586 // Send response
587 sendMessage(&msg);
588 }
589
590 /**
591 * Setup encryption with client
592 */
593 void MobileDeviceSession::setupEncryption(NXCPMessage *request)
594 {
595 NXCPMessage msg;
596
597 #ifdef _WITH_ENCRYPTION
598 m_dwEncryptionRqId = request->getId();
599 m_dwEncryptionResult = RCC_TIMEOUT;
600 if (m_condEncryptionSetup == INVALID_CONDITION_HANDLE)
601 m_condEncryptionSetup = ConditionCreate(FALSE);
602
603 // Send request for session key
604 PrepareKeyRequestMsg(&msg, g_pServerKey, request->getFieldAsUInt16(VID_USE_X509_KEY_FORMAT) != 0);
605 msg.setId(request->getId());
606 sendMessage(&msg);
607 msg.deleteAllFields();
608
609 // Wait for encryption setup
610 ConditionWait(m_condEncryptionSetup, 30000);
611
612 // Send response
613 msg.setCode(CMD_REQUEST_COMPLETED);
614 msg.setId(request->getId());
615 msg.setField(VID_RCC, m_dwEncryptionResult);
616 #else /* _WITH_ENCRYPTION not defined */
617 msg.setCode(CMD_REQUEST_COMPLETED);
618 msg.setId(request->getId());
619 msg.setField(VID_RCC, RCC_NO_ENCRYPTION_SUPPORT);
620 #endif
621
622 sendMessage(&msg);
623 }
624
625 /**
626 * Update device system information
627 */
628 void MobileDeviceSession::updateDeviceInfo(NXCPMessage *request)
629 {
630 NXCPMessage msg;
631
632 // Prepare response message
633 msg.setCode(CMD_REQUEST_COMPLETED);
634 msg.setId(request->getId());
635
636 MobileDevice *device = (MobileDevice *)FindObjectById(m_deviceObjectId, OBJECT_MOBILEDEVICE);
637 if (device != NULL)
638 {
639 device->updateSystemInfo(request);
640 msg.setField(VID_RCC, RCC_SUCCESS);
641 }
642 else
643 {
644 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
645 }
646
647 sendMessage(&msg);
648 }
649
650 /**
651 * Update device status
652 */
653 void MobileDeviceSession::updateDeviceStatus(NXCPMessage *request)
654 {
655 NXCPMessage msg;
656
657 // Prepare response message
658 msg.setCode(CMD_REQUEST_COMPLETED);
659 msg.setId(request->getId());
660
661 MobileDevice *device = (MobileDevice *)FindObjectById(m_deviceObjectId, OBJECT_MOBILEDEVICE);
662 if (device != NULL)
663 {
664 device->updateStatus(request);
665 msg.setField(VID_RCC, RCC_SUCCESS);
666 }
667 else
668 {
669 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
670 }
671
672 sendMessage(&msg);
673 }
674
675 /**
676 * Push DCI data
677 */
678 void MobileDeviceSession::pushData(NXCPMessage *request)
679 {
680 NXCPMessage msg;
681
682 msg.setCode(CMD_REQUEST_COMPLETED);
683 msg.setId(request->getId());
684
685 MobileDevice *device = (MobileDevice *)FindObjectById(m_deviceObjectId, OBJECT_MOBILEDEVICE);
686 if (device != NULL)
687 {
688 int count = (int)request->getFieldAsUInt32(VID_NUM_ITEMS);
689 if (count > 0)
690 {
691 DCItem **dciList = (DCItem **)malloc(sizeof(DCItem *) * count);
692 TCHAR **valueList = (TCHAR **)malloc(sizeof(TCHAR *) * count);
693 memset(valueList, 0, sizeof(TCHAR *) * count);
694
695 int i;
696 UINT32 varId = VID_PUSH_DCI_DATA_BASE;
697 bool ok = true;
698 for(i = 0; (i < count) && ok; i++)
699 {
700 ok = false;
701
702 // find DCI by ID or name (if ID==0)
703 UINT32 dciId = request->getFieldAsUInt32(varId++);
704 DCObject *pItem;
705 if (dciId != 0)
706 {
707 pItem = device->getDCObjectById(dciId);
708 }
709 else
710 {
711 TCHAR name[MAX_PARAM_NAME];
712 request->getFieldAsString(varId++, name, MAX_PARAM_NAME);
713 pItem = device->getDCObjectByName(name);
714 }
715
716 if ((pItem != NULL) && (pItem->getType() == DCO_TYPE_ITEM))
717 {
718 if (pItem->getDataSource() == DS_PUSH_AGENT)
719 {
720 dciList[i] = (DCItem *)pItem;
721 valueList[i] = request->getFieldAsString(varId++);
722 ok = true;
723 }
724 else
725 {
726 msg.setField(VID_RCC, RCC_NOT_PUSH_DCI);
727 }
728 }
729 else
730 {
731 msg.setField(VID_RCC, RCC_INVALID_DCI_ID);
732 }
733 }
734
735 // If all items was checked OK, push data
736 if (ok)
737 {
738 time_t t = 0;
739 int ft = request->getFieldType(VID_TIMESTAMP);
740 if (ft == NXCP_DT_INT32)
741 {
742 t = (time_t)request->getFieldAsUInt32(VID_TIMESTAMP);
743 }
744 else if (ft == NXCP_DT_STRING)
745 {
746 char ts[256];
747 request->getFieldAsMBString(VID_TIMESTAMP, ts, 256);
748
749 struct tm timeBuff;
750 if (strptime(ts, "%Y/%m/%d %H:%M:%S", &timeBuff) != NULL)
751 {
752 timeBuff.tm_isdst = -1;
753 t = timegm(&timeBuff);
754 }
755 }
756 if (t == 0)
757 {
758 time(&t);
759 }
760
761 for(i = 0; i < count; i++)
762 {
763 if (_tcslen(valueList[i]) >= MAX_DCI_STRING_VALUE)
764 valueList[i][MAX_DCI_STRING_VALUE - 1] = 0;
765 device->processNewDCValue(dciList[i], t, valueList[i]);
766 dciList[i]->setLastPollTime(t);
767 }
768 msg.setField(VID_RCC, RCC_SUCCESS);
769 }
770 else
771 {
772 msg.setField(VID_FAILED_DCI_INDEX, i - 1);
773 }
774
775 // Cleanup
776 for(i = 0; i < count; i++)
777 safe_free(valueList[i]);
778 safe_free(valueList);
779 free(dciList);
780 }
781 else
782 {
783 msg.setField(VID_RCC, RCC_INVALID_ARGUMENT);
784 }
785 }
786 else
787 {
788 msg.setField(VID_RCC, RCC_INVALID_OBJECT_ID);
789 }
790
791 sendMessage(&msg);
792 }