75cfca50a024513d4a6b4bcd3bac4326b369c958
[public/netxms.git] / src / libnetxms / tools.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 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: tools.cpp
20 **
21 **/
22
23 #include "libnetxms.h"
24 #include <stdarg.h>
25 #include <nms_agent.h>
26 #include <nms_threads.h>
27
28 #ifdef _WIN32
29 #include <psapi.h>
30 #include <netxms-regex.h>
31 #define read _read
32 #define close _close
33 #else
34 #include <regex.h>
35 #endif
36
37 #if !defined(_WIN32) && !defined(UNDER_CE)
38 #include <sys/time.h>
39 #endif
40
41 #if HAVE_SYS_UTSNAME_H
42 #include <sys/utsname.h>
43 #endif
44
45 #if HAVE_POLL_H
46 #include <poll.h>
47 #endif
48
49 #ifdef _WIN32
50 # ifndef __GNUC__
51 # define EPOCHFILETIME (116444736000000000i64)
52 # else
53 # define EPOCHFILETIME (116444736000000000LL)
54 # endif
55 #endif
56
57
58 //
59 // Calculate number of bits in netmask (in host byte order)
60 //
61
62 int LIBNETXMS_EXPORTABLE BitsInMask(DWORD dwMask)
63 {
64 int bits;
65 DWORD dwTemp;
66
67 for(bits = 0, dwTemp = dwMask; dwTemp != 0; bits++, dwTemp <<= 1);
68 return bits;
69 }
70
71
72 //
73 // Convert IP address from binary form (host bytes order) to string
74 //
75
76 TCHAR LIBNETXMS_EXPORTABLE *IpToStr(DWORD dwAddr, TCHAR *szBuffer)
77 {
78 static TCHAR szInternalBuffer[32];
79 TCHAR *szBufPtr;
80
81 szBufPtr = szBuffer == NULL ? szInternalBuffer : szBuffer;
82 _sntprintf(szBufPtr, 32, _T("%d.%d.%d.%d"), dwAddr >> 24, (dwAddr >> 16) & 255,
83 (dwAddr >> 8) & 255, dwAddr & 255);
84 return szBufPtr;
85 }
86
87
88 //
89 // Duplicate memory block
90 //
91
92 void LIBNETXMS_EXPORTABLE *nx_memdup(const void *pData, DWORD dwSize)
93 {
94 void *pNewData;
95
96 pNewData = malloc(dwSize);
97 memcpy(pNewData, pData, dwSize);
98 return pNewData;
99 }
100
101
102 //
103 // Swap two memory blocks
104 //
105
106 void LIBNETXMS_EXPORTABLE nx_memswap(void *pBlock1, void *pBlock2, DWORD dwSize)
107 {
108 void *pTemp;
109
110 pTemp = malloc(dwSize);
111 memcpy(pTemp, pBlock1, dwSize);
112 memcpy(pBlock1, pBlock2, dwSize);
113 memcpy(pBlock2, pTemp, dwSize);
114 free(pTemp);
115 }
116
117
118 //
119 // Match string against pattern with * and ? metasymbols
120 //
121
122 static BOOL MatchStringEngine(const TCHAR *pattern, const TCHAR *string)
123 {
124 const TCHAR *SPtr, *MPtr, *BPtr, *EPtr;
125 BOOL bFinishScan;
126
127 SPtr = string;
128 MPtr = pattern;
129
130 while(*MPtr != 0)
131 {
132 switch(*MPtr)
133 {
134 case _T('?'):
135 if (*SPtr != 0)
136 {
137 SPtr++;
138 MPtr++;
139 }
140 else
141 return FALSE;
142 break;
143 case _T('*'):
144 while(*MPtr == _T('*'))
145 MPtr++;
146 if (*MPtr == 0)
147 return TRUE;
148 while(*MPtr == _T('?')) // Handle "*?" case
149 {
150 if (*SPtr != 0)
151 SPtr++;
152 else
153 return FALSE;
154 MPtr++;
155 break;
156 }
157 BPtr = MPtr; // Text block begins here
158 while((*MPtr != 0) && (*MPtr != _T('?')) && (*MPtr != _T('*')))
159 MPtr++; // Find the end of text block
160 // Try to find rightmost matching block
161 EPtr = NULL;
162 bFinishScan = FALSE;
163 do
164 {
165 while(1)
166 {
167 while((*SPtr != 0) && (*SPtr != *BPtr))
168 SPtr++;
169 if (_tcslen(SPtr) < (size_t)(MPtr - BPtr))
170 {
171 if (EPtr == NULL)
172 {
173 return FALSE; // Length of remained text less than remaining pattern
174 }
175 else
176 {
177 SPtr = EPtr; // Revert back to last match
178 bFinishScan = TRUE;
179 break;
180 }
181 }
182 if (!memcmp(BPtr, SPtr, (MPtr - BPtr) * sizeof(TCHAR)))
183 break;
184 SPtr++;
185 }
186 if (!bFinishScan)
187 {
188 SPtr += (MPtr - BPtr); // Increment SPtr because we alredy match current fragment
189 EPtr = SPtr; // Remember current point
190 }
191 }
192 while(!bFinishScan);
193 break;
194 default:
195 if (*MPtr == *SPtr)
196 {
197 SPtr++;
198 MPtr++;
199 }
200 else
201 return FALSE;
202 break;
203 }
204 }
205
206 return *SPtr == 0 ? TRUE : FALSE;
207 }
208
209 BOOL LIBNETXMS_EXPORTABLE MatchString(const TCHAR *pattern,
210 const TCHAR *string,
211 BOOL matchCase)
212 {
213 if (matchCase)
214 return MatchStringEngine(pattern, string);
215 else
216 {
217 TCHAR *tp, *ts;
218 BOOL bResult;
219
220 tp = _tcsdup(pattern);
221 ts = _tcsdup(string);
222 _tcsupr(tp);
223 _tcsupr(ts);
224 bResult = MatchStringEngine(tp, ts);
225 free(tp);
226 free(ts);
227 return bResult;
228 }
229 }
230
231
232 //
233 // Strip whitespaces and tabs off the string
234 //
235
236 void LIBNETXMS_EXPORTABLE StrStrip(TCHAR *str)
237 {
238 int i;
239
240 for(i=0;(str[i]!=0)&&((str[i]==_T(' '))||(str[i]==_T('\t')));i++);
241 if (i>0)
242 memmove(str,&str[i],(_tcslen(&str[i])+1) * sizeof(TCHAR));
243 for(i=(int)_tcslen(str)-1;(i>=0)&&((str[i]==_T(' '))||(str[i]==_T('\t')));i--);
244 str[i+1]=0;
245 }
246
247
248 //
249 // Strip whitespaces and tabs off the string
250 //
251
252 void LIBNETXMS_EXPORTABLE Trim(TCHAR *str)
253 {
254 int i;
255
256 for(i = 0; (str[i] != 0) && _istspace(str[i]); i++);
257 if (i > 0)
258 memmove(str, &str[i], (_tcslen(&str[i]) + 1) * sizeof(TCHAR));
259 for(i = (int)_tcslen(str) - 1; (i >= 0) && _istspace(str[i]); i--);
260 str[i + 1] = 0;
261 }
262
263
264 //
265 // Remove trailing CR/LF or LF from string
266 //
267
268 void LIBNETXMS_EXPORTABLE RemoveTrailingCRLF(TCHAR *str)
269 {
270 if (*str == 0)
271 return;
272
273 TCHAR *p = str + _tcslen(str) - 1;
274 if (*p == '\n')
275 p--;
276 if (*p == '\r')
277 p--;
278 *(p + 1) = 0;
279 }
280
281
282 //
283 // Get current time in milliseconds
284 // Based on timeval.h by Wu Yongwei
285 //
286
287 INT64 LIBNETXMS_EXPORTABLE GetCurrentTimeMs(void)
288 {
289 #ifdef _WIN32
290 FILETIME ft;
291 LARGE_INTEGER li;
292 __int64 t;
293
294 GetSystemTimeAsFileTime(&ft);
295 li.LowPart = ft.dwLowDateTime;
296 li.HighPart = ft.dwHighDateTime;
297 t = li.QuadPart; // In 100-nanosecond intervals
298 t -= EPOCHFILETIME; // Offset to the Epoch time
299 t /= 10000; // Convert to milliseconds
300 #else
301 struct timeval tv;
302 INT64 t;
303
304 gettimeofday(&tv, NULL);
305 t = (INT64)tv.tv_sec * 1000 + (INT64)(tv.tv_usec / 10000);
306 #endif
307
308 return t;
309 }
310
311
312 //
313 // Extract word from line. Extracted word will be placed in buffer.
314 // Returns pointer to the next word or to the null character if end
315 // of line reached.
316 //
317
318 TCHAR LIBNETXMS_EXPORTABLE *ExtractWord(TCHAR *line, TCHAR *buffer)
319 {
320 TCHAR *ptr,*bptr;
321
322 for(ptr=line;(*ptr==_T(' '))||(*ptr==_T('\t'));ptr++); // Skip initial spaces
323 // Copy word to buffer
324 for(bptr=buffer;(*ptr!=_T(' '))&&(*ptr!=_T('\t'))&&(*ptr!=0);ptr++,bptr++)
325 *bptr=*ptr;
326 *bptr=0;
327 return ptr;
328 }
329
330
331 //
332 // Get system error string by call to FormatMessage
333 // (Windows only)
334 //
335
336 #if defined(_WIN32)
337
338 TCHAR LIBNETXMS_EXPORTABLE *GetSystemErrorText(DWORD dwError, TCHAR *pszBuffer, size_t iBufSize)
339 {
340 TCHAR *msgBuf;
341
342 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
343 FORMAT_MESSAGE_FROM_SYSTEM |
344 FORMAT_MESSAGE_IGNORE_INSERTS,
345 NULL, dwError,
346 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
347 (LPTSTR)&msgBuf, 0, NULL) > 0)
348 {
349 msgBuf[_tcscspn(msgBuf, _T("\r\n"))] = 0;
350 nx_strncpy(pszBuffer, msgBuf, iBufSize);
351 LocalFree(msgBuf);
352 }
353 else
354 {
355 _sntprintf(pszBuffer, iBufSize, _T("MSG 0x%08X - Unable to find message text"), dwError);
356 }
357 return pszBuffer;
358 }
359
360 #endif
361
362
363 //
364 // daemon() implementation for systems which doesn't have one
365 //
366
367 #if !(HAVE_DAEMON) && !defined(_NETWARE) && !defined(_WIN32)
368
369 int LIBNETXMS_EXPORTABLE daemon(int nochdir, int noclose)
370 {
371 int pid;
372
373 if ((pid = fork()) < 0)
374 return -1;
375 if (pid != 0)
376 exit(0); // Terminate parent
377
378 setsid();
379
380 if (!nochdir)
381 chdir("/");
382
383 if (!noclose)
384 {
385 fclose(stdin); // don't need stdin, stdout, stderr
386 fclose(stdout);
387 fclose(stderr);
388 }
389
390 return 0;
391 }
392
393 #endif
394
395
396 //
397 // Check if given name is a valid object name
398 //
399
400 BOOL LIBNETXMS_EXPORTABLE IsValidObjectName(const TCHAR *pszName, BOOL bExtendedChars)
401 {
402 static TCHAR szValidCharacters[] = _T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_- @()./");
403 static TCHAR szInvalidCharacters[] = _T("\x01\x02\x03\x04\x05\x06\x07")
404 _T("\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F")
405 _T("\x10\x11\x12\x13\x14\x15\x16\x17")
406 _T("\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")
407 _T("|\"'*%#\\`;?<>=");
408
409 return (pszName[0] != 0) && (bExtendedChars ? (_tcscspn(pszName, szInvalidCharacters) == _tcslen(pszName)) : (_tcsspn(pszName, szValidCharacters) == _tcslen(pszName)));
410 }
411
412
413 //
414 // Check if given name is a valid script name
415 //
416
417 BOOL LIBNETXMS_EXPORTABLE IsValidScriptName(const TCHAR *pszName)
418 {
419 static TCHAR szValidCharacters[] = _T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_:");
420 return (pszName[0] != 0) && (!isdigit(pszName[0])) && (pszName[0] != ':') &&
421 (_tcsspn(pszName, szValidCharacters) == _tcslen(pszName));
422 }
423
424
425 //
426 // Convert 6-byte MAC address to text representation
427 //
428
429 void LIBNETXMS_EXPORTABLE MACToStr(BYTE *pData, TCHAR *pStr)
430 {
431 DWORD i;
432 TCHAR *pCurr;
433
434 for(i = 0, pCurr = pStr; i < 6; i++)
435 {
436 *pCurr++ = bin2hex(pData[i] >> 4);
437 *pCurr++ = bin2hex(pData[i] & 15);
438 *pCurr++ = _T(':');
439 }
440 *(pCurr - 1) = 0;
441 }
442
443
444 //
445 // Convert byte array to text representation
446 //
447
448 TCHAR LIBNETXMS_EXPORTABLE *BinToStr(BYTE *pData, DWORD dwSize, TCHAR *pStr)
449 {
450 DWORD i;
451 TCHAR *pCurr;
452
453 for(i = 0, pCurr = pStr; i < dwSize; i++)
454 {
455 *pCurr++ = bin2hex(pData[i] >> 4);
456 *pCurr++ = bin2hex(pData[i] & 15);
457 }
458 *pCurr = 0;
459 return pStr;
460 }
461
462
463 //
464 // Convert string of hexadecimal digits to byte array
465 //
466
467 DWORD LIBNETXMS_EXPORTABLE StrToBin(const TCHAR *pStr, BYTE *pData, DWORD dwSize)
468 {
469 DWORD i;
470 const TCHAR *pCurr;
471
472 memset(pData, 0, dwSize);
473 for(i = 0, pCurr = pStr; (i < dwSize) && (*pCurr != 0); i++)
474 {
475 pData[i] = hex2bin(*pCurr) << 4;
476 pCurr++;
477 pData[i] |= hex2bin(*pCurr);
478 pCurr++;
479 }
480 return i;
481 }
482
483
484 //
485 // Translate string
486 // NOTE: replacement string shouldn't be longer than original
487 //
488
489 void LIBNETXMS_EXPORTABLE TranslateStr(TCHAR *pszString, const TCHAR *pszSubStr, const TCHAR *pszReplace)
490 {
491 TCHAR *pszSrc, *pszDst;
492 int iSrcLen, iRepLen;
493
494 iSrcLen = (int)_tcslen(pszSubStr);
495 iRepLen = (int)_tcslen(pszReplace);
496 for(pszSrc = pszString, pszDst = pszString; *pszSrc != 0;)
497 {
498 if (!_tcsncmp(pszSrc, pszSubStr, iSrcLen))
499 {
500 memcpy(pszDst, pszReplace, sizeof(TCHAR) * iRepLen);
501 pszSrc += iSrcLen;
502 pszDst += iRepLen;
503 }
504 else
505 {
506 *pszDst++ = *pszSrc++;
507 }
508 }
509 *pszDst = 0;
510 }
511
512
513 //
514 // Get size of file in bytes
515 //
516
517 QWORD LIBNETXMS_EXPORTABLE FileSize(const TCHAR *pszFileName)
518 {
519 #ifdef _WIN32
520 HANDLE hFind;
521 WIN32_FIND_DATA fd;
522 #else
523 struct stat fileInfo;
524 #endif
525
526 #ifdef _WIN32
527 hFind = FindFirstFile(pszFileName, &fd);
528 if (hFind == INVALID_HANDLE_VALUE)
529 return 0;
530 FindClose(hFind);
531
532 return (unsigned __int64)fd.nFileSizeLow + ((unsigned __int64)fd.nFileSizeHigh << 32);
533 #else
534 if (_tstat(pszFileName, &fileInfo) == -1)
535 return 0;
536
537 return (QWORD)fileInfo.st_size;
538 #endif
539 }
540
541
542 //
543 // Get pointer to clean file name (without path specification)
544 //
545
546 TCHAR LIBNETXMS_EXPORTABLE *GetCleanFileName(TCHAR *pszFileName)
547 {
548 TCHAR *ptr;
549
550 ptr = pszFileName + _tcslen(pszFileName);
551 while((ptr >= pszFileName) && (*ptr != _T('/')) && (*ptr != _T('\\')) && (*ptr != _T(':')))
552 ptr--;
553 return (ptr + 1);
554 }
555
556
557 //
558 // Translate DCI data type from text form to code
559 //
560
561 int LIBNETXMS_EXPORTABLE NxDCIDataTypeFromText(const TCHAR *pszText)
562 {
563 static const TCHAR *m_pszValidTypes[] = { _T("INT"), _T("UINT"), _T("INT64"),
564 _T("UINT64"), _T("STRING"),
565 _T("FLOAT"), NULL };
566 int i;
567
568 for(i = 0; m_pszValidTypes[i] != NULL; i++)
569 if (!_tcsicmp(pszText, m_pszValidTypes[i]))
570 return i;
571 return -1; // Invalid data type
572 }
573
574
575 //
576 // Extended send() - send all data even if single call to send()
577 // cannot handle them all
578 //
579
580 int LIBNETXMS_EXPORTABLE SendEx(SOCKET nSocket, const void *pBuff,
581 size_t nSize, int nFlags)
582 {
583 int nLeft = (int)nSize;
584 int nRet;
585
586 do
587 {
588 retry:
589 #ifdef MSG_NOSIGNAL
590 nRet = send(nSocket, ((char *)pBuff) + (nSize - nLeft), nLeft, nFlags | MSG_NOSIGNAL);
591 #else
592 nRet = send(nSocket, ((char *)pBuff) + (nSize - nLeft), nLeft, nFlags);
593 #endif
594 if (nRet <= 0)
595 {
596 if (WSAGetLastError() == WSAEWOULDBLOCK)
597 {
598 // Wait until socket becomes available for writing
599 struct timeval tv;
600 fd_set wfds;
601
602 tv.tv_sec = 60;
603 tv.tv_usec = 0;
604 FD_ZERO(&wfds);
605 FD_SET(nSocket, &wfds);
606 nRet = select(SELECT_NFDS(nSocket + 1), NULL, &wfds, NULL, &tv);
607 if ((nRet > 0) || ((nRet == -1) && (errno == EINTR)))
608 goto retry;
609 }
610 break;
611 }
612 nLeft -= nRet;
613 } while (nLeft > 0);
614
615 return nLeft == 0 ? (int)nSize : nRet;
616 }
617
618
619 //
620 // Extended recv() - receive data with timeout
621 //
622
623 int LIBNETXMS_EXPORTABLE RecvEx(SOCKET nSocket, const void *pBuff,
624 size_t nSize, int nFlags, DWORD dwTimeout)
625 {
626 int iErr;
627 #if HAVE_POLL
628 struct pollfd fds;
629 #else
630 struct timeval tv;
631 fd_set rdfs;
632 #endif
633 #ifndef _WIN32
634 QWORD qwStartTime;
635 DWORD dwElapsed;
636 #endif
637
638 // I've seen on Linux that poll() may hang if fds.fd == -1,
639 // so we check this ourselves
640 if (nSocket == -1)
641 return -1;
642
643 if (dwTimeout != INFINITE)
644 {
645 #if HAVE_POLL
646 fds.fd = nSocket;
647 fds.events = POLLIN;
648 fds.revents = POLLIN;
649 do
650 {
651 qwStartTime = GetCurrentTimeMs();
652 iErr = poll(&fds, 1, dwTimeout);
653 if ((iErr != -1) || (errno != EINTR))
654 break;
655 dwElapsed = GetCurrentTimeMs() - qwStartTime;
656 dwTimeout -= min(dwTimeout, dwElapsed);
657 } while(dwTimeout > 0);
658 #else
659 FD_ZERO(&rdfs);
660 FD_SET(nSocket, &rdfs);
661 #ifdef _WIN32
662 tv.tv_sec = dwTimeout / 1000;
663 tv.tv_usec = (dwTimeout % 1000) * 1000;
664 iErr = select(SELECT_NFDS(nSocket + 1), &rdfs, NULL, NULL, &tv);
665 #else
666 do
667 {
668 tv.tv_sec = dwTimeout / 1000;
669 tv.tv_usec = (dwTimeout % 1000) * 1000;
670 qwStartTime = GetCurrentTimeMs();
671 iErr = select(SELECT_NFDS(nSocket + 1), &rdfs, NULL, NULL, &tv);
672 if ((iErr != -1) || (errno != EINTR))
673 break;
674 dwElapsed = GetCurrentTimeMs() - qwStartTime;
675 dwTimeout -= min(dwTimeout, dwElapsed);
676 } while(dwTimeout > 0);
677 #endif
678 #endif
679 if (iErr > 0)
680 {
681 #ifdef _WIN32
682 iErr = recv(nSocket, (char *)pBuff, (int)nSize, nFlags);
683 #else
684 do
685 {
686 iErr = recv(nSocket, (char *)pBuff, nSize, nFlags);
687 } while((iErr == -1) && (errno == EINTR));
688 #endif
689 }
690 else
691 {
692 iErr = -2;
693 }
694 }
695 else
696 {
697 #ifdef _WIN32
698 iErr = recv(nSocket, (char *)pBuff, (int)nSize, nFlags);
699 #else
700 do
701 {
702 iErr = recv(nSocket, (char *)pBuff, nSize, nFlags);
703 } while((iErr == -1) && (errno == EINTR));
704 #endif
705 }
706
707 return iErr;
708 }
709
710
711 //
712 // Connect with given timeout
713 // Sets socket to non-blocking mode
714 //
715
716 int LIBNETXMS_EXPORTABLE ConnectEx(SOCKET s, struct sockaddr *addr, int len, DWORD timeout)
717 {
718 SetSocketNonBlocking(s);
719 int rc = connect(s, addr, len);
720 if (rc == -1)
721 {
722 if ((WSAGetLastError() == WSAEWOULDBLOCK) || (WSAGetLastError() == WSAEINPROGRESS))
723 {
724 #ifndef _WIN32
725 QWORD qwStartTime;
726 DWORD dwElapsed;
727 #endif
728
729 #if HAVE_POLL
730 struct pollfd fds;
731
732 fds.fd = s;
733 fds.events = POLLOUT;
734 fds.revents = POLLOUT;
735 do
736 {
737 qwStartTime = GetCurrentTimeMs();
738 rc = poll(&fds, 1, timeout);
739 if ((rc != -1) || (errno != EINTR))
740 break;
741 dwElapsed = GetCurrentTimeMs() - qwStartTime;
742 timeout -= min(timeout, dwElapsed);
743 } while(timeout > 0);
744 #else
745 struct timeval tv;
746 fd_set wrfs;
747
748 FD_ZERO(&wrfs);
749 FD_SET(s, &wrfs);
750 #ifdef _WIN32
751 tv.tv_sec = timeout / 1000;
752 tv.tv_usec = (timeout % 1000) * 1000;
753 rc = select(SELECT_NFDS(s + 1), NULL, &wrfs, NULL, &tv);
754 #else
755 do
756 {
757 tv.tv_sec = timeout / 1000;
758 tv.tv_usec = (timeout % 1000) * 1000;
759 qwStartTime = GetCurrentTimeMs();
760 rc = select(SELECT_NFDS(s + 1), NULL, &wrfs, NULL, &tv);
761 if ((rc != -1) || (errno != EINTR))
762 break;
763 dwElapsed = GetCurrentTimeMs() - qwStartTime;
764 timeout -= min(timeout, dwElapsed);
765 } while(timeout > 0);
766 #endif
767 #endif
768 if (rc == 0) // timeout, return error
769 rc = -1;
770 }
771 }
772 return rc;
773 }
774
775
776 //
777 // Resolve host name to IP address
778 //
779
780 DWORD LIBNETXMS_EXPORTABLE ResolveHostName(const TCHAR *pszName)
781 {
782 DWORD dwAddr;
783 struct hostent *hs;
784 #ifdef UNICODE
785 char szBuffer[256];
786
787 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
788 pszName, -1, szBuffer, 256, NULL, NULL);
789 dwAddr = inet_addr(szBuffer);
790 #else
791 dwAddr = inet_addr(pszName);
792 #endif
793 if ((dwAddr == INADDR_NONE) || (dwAddr == INADDR_ANY))
794 {
795 #ifdef UNICODE
796 hs = gethostbyname(szBuffer);
797 #else
798 hs = gethostbyname(pszName);
799 #endif
800 if (hs != NULL)
801 {
802 memcpy(&dwAddr, hs->h_addr, sizeof(DWORD));
803 }
804 else
805 {
806 dwAddr = INADDR_NONE;
807 }
808 }
809
810 return dwAddr;
811 }
812
813
814 #ifndef VER_PLATFORM_WIN32_WINDOWS
815 #define VER_PLATFORM_WIN32_WINDOWS 1
816 #endif
817 #ifndef VER_PLATFORM_WIN32_CE
818 #define VER_PLATFORM_WIN32_CE 3
819 #endif
820 #ifndef SM_SERVERR2
821 #define SM_SERVERR2 89
822 #endif
823
824
825 //
826 // Get OS name and version
827 //
828
829 void LIBNETXMS_EXPORTABLE GetOSVersionString(TCHAR *pszBuffer, int nBufSize)
830 {
831 int nSize = nBufSize - 1;
832
833 memset(pszBuffer, 0, nBufSize * sizeof(TCHAR));
834
835 #if defined(_WIN32)
836 OSVERSIONINFO ver;
837
838 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
839 GetVersionEx(&ver);
840 switch(ver.dwPlatformId)
841 {
842 case VER_PLATFORM_WIN32_WINDOWS:
843 _sntprintf(pszBuffer, nSize, _T("Win%s"), ver.dwMinorVersion == 0 ? _T("95") :
844 (ver.dwMinorVersion == 10 ? _T("98") :
845 (ver.dwMinorVersion == 90 ? _T("Me") : _T("9x"))));
846 break;
847 case VER_PLATFORM_WIN32_NT:
848 _sntprintf(pszBuffer, nSize, _T("WinNT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
849 break;
850 #ifdef VER_PLATFORM_WIN32_CE
851 case VER_PLATFORM_WIN32_CE:
852 _sntprintf(pszBuffer, nSize, _T("WinCE %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
853 break;
854 #endif
855 default:
856 _sntprintf(pszBuffer, nSize, _T("WinX %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
857 break;
858 }
859 #elif defined(_NETWARE)
860 struct utsname un;
861
862 uname(&un);
863 _sntprintf(pszBuffer, nSize, _T("NetWare %d.%d"), un.netware_major, un.netware_minor);
864 if (un.servicepack > 0)
865 {
866 int nLen = (int)_tcslen(pszBuffer);
867 nSize -= nLen;
868 if (nSize > 0)
869 _sntprintf(&pszBuffer[nLen], nSize, _T(" sp%d"), un.servicepack);
870 }
871 #else
872 struct utsname un;
873
874 uname(&un);
875 #ifdef UNICODE
876 char buf[1024];
877 snprintf(buf, 1024, "%s %s", un.sysname, un.release);
878 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buf, -1, pszBuffer, nSize);
879 #else
880 snprintf(pszBuffer, nSize, "%s %s", un.sysname, un.release);
881 #endif
882 #endif
883 }
884
885
886 //
887 // Get more specific Windows version string
888 //
889
890 #ifdef _WIN32
891
892 BOOL LIBNETXMS_EXPORTABLE GetWindowsVersionString(TCHAR *versionString, int strSize)
893 {
894 OSVERSIONINFOEX ver;
895 TCHAR buffer[256];
896
897 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
898 if (!GetVersionEx((OSVERSIONINFO *)&ver))
899 return FALSE;
900
901 switch(ver.dwMajorVersion)
902 {
903 case 5:
904 switch(ver.dwMinorVersion)
905 {
906 case 0:
907 _tcscpy(buffer, _T("2000"));
908 break;
909 case 1:
910 _tcscpy(buffer, _T("XP"));
911 break;
912 case 2:
913 _tcscpy(buffer, (GetSystemMetrics(SM_SERVERR2) != 0) ? _T("Server 2003 R2") : _T("Server 2003"));
914 break;
915 default:
916 _sntprintf(buffer, 256, _T("NT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
917 break;
918 }
919 break;
920 case 6:
921 switch(ver.dwMinorVersion)
922 {
923 case 0:
924 _tcscpy(buffer, (ver.wProductType == VER_NT_WORKSTATION) ? _T("Vista") : _T("Server 2008"));
925 break;
926 case 1:
927 _tcscpy(buffer, (ver.wProductType == VER_NT_WORKSTATION) ? _T("7") : _T("Server 2008 R2"));
928 break;
929 default:
930 _sntprintf(buffer, 256, _T("NT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
931 break;
932 }
933 break;
934 default:
935 _sntprintf(buffer, 256, _T("NT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
936 break;
937 }
938
939 _sntprintf(versionString, strSize, _T("Windows %s Build %d %s"), buffer, ver.dwBuildNumber, ver.szCSDVersion);
940 StrStrip(versionString);
941 return TRUE;
942 }
943
944 #endif
945
946
947 //
948 // Count number of characters in string
949 //
950
951 int LIBNETXMS_EXPORTABLE NumChars(const TCHAR *pszStr, int ch)
952 {
953 const TCHAR *p;
954 int nCount;
955
956 for(p = pszStr, nCount = 0; *p != 0; p++)
957 if (*p == ch)
958 nCount++;
959 return nCount;
960 }
961
962
963 //
964 // Match string against regexp
965 //
966
967 BOOL LIBNETXMS_EXPORTABLE RegexpMatch(const TCHAR *pszStr, const TCHAR *pszExpr, BOOL bMatchCase)
968 {
969 #ifdef UNICODE
970 regex_t preg;
971 char *mbStr, *mbExpr;
972 BOOL bResult = FALSE;
973
974 mbStr = MBStringFromWideString(pszStr);
975 mbExpr = MBStringFromWideString(pszExpr);
976 if (regcomp(&preg, mbExpr, bMatchCase ? REG_EXTENDED | REG_NOSUB : REG_EXTENDED | REG_NOSUB | REG_ICASE) == 0)
977 {
978 if (regexec(&preg, mbStr, 0, NULL, 0) == 0) // MATCH
979 bResult = TRUE;
980 regfree(&preg);
981 }
982 free(mbStr);
983 free(mbExpr);
984
985 return bResult;
986 #else
987 regex_t preg;
988 BOOL bResult = FALSE;
989
990 if (regcomp(&preg, pszExpr, bMatchCase ? REG_EXTENDED | REG_NOSUB : REG_EXTENDED | REG_NOSUB | REG_ICASE) == 0)
991 {
992 if (regexec(&preg, pszStr, 0, NULL, 0) == 0) // MATCH
993 bResult = TRUE;
994 regfree(&preg);
995 }
996
997 return bResult;
998 #endif
999 }
1000
1001
1002 //
1003 // Translate given code to text
1004 //
1005
1006 const TCHAR LIBNETXMS_EXPORTABLE *CodeToText(int iCode, CODE_TO_TEXT *pTranslator, const TCHAR *pszDefaultText)
1007 {
1008 int i;
1009
1010 for(i = 0; pTranslator[i].text != NULL; i++)
1011 if (pTranslator[i].code == iCode)
1012 return pTranslator[i].text;
1013 return pszDefaultText;
1014 }
1015
1016
1017 //
1018 // Extract option value from string of form option=value;option=value;...
1019 //
1020
1021 BOOL LIBNETXMS_EXPORTABLE ExtractNamedOptionValue(const TCHAR *optString, const TCHAR *option, TCHAR *buffer, int bufSize)
1022 {
1023 int state, pos;
1024 const TCHAR *curr, *start;
1025 TCHAR temp[256];
1026
1027 for(curr = start = optString, pos = 0, state = 0; *curr != 0; curr++)
1028 {
1029 switch(*curr)
1030 {
1031 case _T(';'): // Next option
1032 if (state == 1)
1033 {
1034 buffer[pos] = 0;
1035 StrStrip(buffer);
1036 return TRUE;
1037 }
1038 state = 0;
1039 start = curr + 1;
1040 break;
1041 case _T('='):
1042 if (state == 0)
1043 {
1044 _tcsncpy(temp, start, curr - start);
1045 temp[curr - start] = 0;
1046 StrStrip(temp);
1047 if (!_tcsicmp(option, temp))
1048 state = 1;
1049 else
1050 state = 2;
1051 }
1052 else if ((state == 1) && (pos < bufSize - 1))
1053 {
1054 buffer[pos++] = _T('=');
1055 }
1056 break;
1057 default:
1058 if ((state == 1) && (pos < bufSize - 1))
1059 buffer[pos++] = *curr;
1060 break;
1061 }
1062 }
1063
1064 if (state == 1)
1065 {
1066 buffer[pos] = 0;
1067 StrStrip(buffer);
1068 return TRUE;
1069 }
1070
1071 return FALSE;
1072 }
1073
1074 BOOL LIBNETXMS_EXPORTABLE ExtractNamedOptionValueAsBool(const TCHAR *optString, const TCHAR *option, BOOL defVal)
1075 {
1076 TCHAR buffer[256];
1077
1078 if (ExtractNamedOptionValue(optString, option, buffer, 256))
1079 {
1080 if (!_tcsicmp(buffer, _T("yes")) || !_tcsicmp(buffer, _T("true")))
1081 return TRUE;
1082 return FALSE;
1083 }
1084 return defVal;
1085 }
1086
1087 long LIBNETXMS_EXPORTABLE ExtractNamedOptionValueAsInt(const TCHAR *optString, const TCHAR *option, long defVal)
1088 {
1089 TCHAR buffer[256], *eptr;
1090 long val;
1091
1092 if (ExtractNamedOptionValue(optString, option, buffer, 256))
1093 {
1094 val = _tcstol(buffer, &eptr, 0);
1095 if (*eptr == 0)
1096 return val;
1097 }
1098 return defVal;
1099 }
1100
1101
1102 //
1103 // Split string
1104 //
1105
1106 TCHAR LIBNETXMS_EXPORTABLE **SplitString(const TCHAR *source, TCHAR sep, int *numStrings)
1107 {
1108 TCHAR **strings;
1109
1110 *numStrings = NumChars(source, sep) + 1;
1111 strings = (TCHAR **)malloc(sizeof(TCHAR *) * (*numStrings));
1112 for(int n = 0, i = 0; n < *numStrings; n++, i++)
1113 {
1114 int start = i;
1115 while((source[i] != sep) && (source[i] != 0))
1116 i++;
1117 int len = i - start;
1118 strings[n] = (TCHAR *)malloc(sizeof(TCHAR) * (len + 1));
1119 memcpy(strings[n], &source[start], len * sizeof(TCHAR));
1120 strings[n][len] = 0;
1121 }
1122 return strings;
1123 }
1124
1125
1126 //
1127 // Decrypt password
1128 //
1129
1130 BOOL LIBNETXMS_EXPORTABLE DecryptPassword(const TCHAR *login, const TCHAR *encryptedPasswd, TCHAR *decryptedPasswd)
1131 {
1132 if (_tcslen(encryptedPasswd) != 44)
1133 return FALSE;
1134
1135 #ifdef UNICODE
1136 char *mbencrypted = MBStringFromWideString(encryptedPasswd);
1137 char *mblogin = MBStringFromWideString(login);
1138 #else
1139 const char *mbencrypted = encryptedPasswd;
1140 const char *mblogin = login;
1141 #endif
1142
1143 BYTE encrypted[32], decrypted[32], key[16];
1144 size_t encSize;
1145 base64_decode(mbencrypted, strlen(mbencrypted), (char *)encrypted, &encSize);
1146 if (encSize != 32)
1147 return FALSE;
1148
1149 CalculateMD5Hash((BYTE *)mblogin, strlen(mblogin), key);
1150 ICEDecryptData(encrypted, 32, decrypted, key);
1151 decrypted[31] = 0;
1152
1153 #ifdef UNICODE
1154 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char *)decrypted, -1, decryptedPasswd, 32);
1155 decryptedPasswd[31] = 0;
1156 free(mbencrypted);
1157 free(mblogin);
1158 #else
1159 nx_strncpy(decryptedPasswd, (char *)decrypted, 32);
1160 #endif
1161
1162 return TRUE;
1163 }
1164
1165
1166 //
1167 // Load file into memory
1168 //
1169
1170 #ifndef UNDER_CE
1171
1172 BYTE LIBNETXMS_EXPORTABLE *LoadFile(const TCHAR *pszFileName, DWORD *pdwFileSize)
1173 {
1174 int fd, iBufPos, iNumBytes, iBytesRead;
1175 BYTE *pBuffer = NULL;
1176 struct stat fs;
1177
1178 fd = _topen(pszFileName, O_RDONLY | O_BINARY);
1179 if (fd != -1)
1180 {
1181 if (fstat(fd, &fs) != -1)
1182 {
1183 pBuffer = (BYTE *)malloc(fs.st_size + 1);
1184 if (pBuffer != NULL)
1185 {
1186 *pdwFileSize = fs.st_size;
1187 for(iBufPos = 0; iBufPos < fs.st_size; iBufPos += iBytesRead)
1188 {
1189 iNumBytes = min(16384, fs.st_size - iBufPos);
1190 if ((iBytesRead = read(fd, &pBuffer[iBufPos], iNumBytes)) < 0)
1191 {
1192 free(pBuffer);
1193 pBuffer = NULL;
1194 break;
1195 }
1196 }
1197 pBuffer[fs.st_size] = 0;
1198 }
1199 }
1200 close(fd);
1201 }
1202 return pBuffer;
1203 }
1204
1205 #endif
1206
1207
1208 //
1209 // open/read/write for Windows CE
1210 //
1211
1212 #ifdef UNDER_CE
1213
1214 int LIBNETXMS_EXPORTABLE _topen(TCHAR *pszName, int nFlags, ...)
1215 {
1216 HANDLE hFile;
1217 DWORD dwAccess, dwDisp;
1218
1219 dwAccess = (nFlags & O_RDONLY) ? GENERIC_READ :
1220 (nFlags & O_WRONLY) ? GENERIC_WRITE :
1221 (nFlags & O_RDWR) ? (GENERIC_READ | GENERIC_WRITE) : 0;
1222 if ((nFlags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
1223 dwDisp = CREATE_ALWAYS;
1224 else if ((nFlags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
1225 dwDisp = CREATE_NEW;
1226 else if ((nFlags & O_CREAT) == O_CREAT)
1227 dwDisp = OPEN_ALWAYS;
1228 else if ((nFlags & O_TRUNC) == O_TRUNC)
1229 dwDisp = TRUNCATE_EXISTING;
1230 else
1231 dwDisp = OPEN_EXISTING;
1232 hFile = CreateFile(pszName, dwAccess, FILE_SHARE_READ, NULL, dwDisp,
1233 FILE_ATTRIBUTE_NORMAL, NULL);
1234 return (hFile == INVALID_HANDLE_VALUE) ? -1 : (int)hFile;
1235 }
1236
1237 int LIBNETXMS_EXPORTABLE read(int hFile, void *pBuffer, size_t nBytes)
1238 {
1239 DWORD dwBytes;
1240
1241 if (ReadFile((HANDLE)hFile, pBuffer, nBytes, &dwBytes, NULL))
1242 return dwBytes;
1243 else
1244 return -1;
1245 }
1246
1247 int LIBNETXMS_EXPORTABLE write(int hFile, void *pBuffer, size_t nBytes)
1248 {
1249 DWORD dwBytes;
1250
1251 if (WriteFile((HANDLE)hFile, pBuffer, nBytes, &dwBytes, NULL))
1252 return dwBytes;
1253 else
1254 return -1;
1255 }
1256
1257 #endif /* UNDER_CE */
1258
1259
1260 //
1261 // Memory debugging functions
1262 //
1263
1264 #ifdef NETXMS_MEMORY_DEBUG
1265
1266 #undef malloc
1267 #undef realloc
1268 #undef free
1269
1270 typedef struct
1271 {
1272 void *pAddr;
1273 char szFile[MAX_PATH];
1274 int nLine;
1275 time_t nAllocTime;
1276 LONG nBytes;
1277 } MEMORY_BLOCK;
1278
1279 static MEMORY_BLOCK *m_pBlockList = NULL;
1280 static DWORD m_dwNumBlocks = 0;
1281 static MUTEX m_mutex;
1282 static time_t m_nStartTime;
1283
1284 void InitMemoryDebugger(void)
1285 {
1286 m_mutex = MutexCreate();
1287 m_nStartTime = time(NULL);
1288 }
1289
1290 static void AddBlock(void *p, char *file, int line, size_t size)
1291 {
1292 m_pBlockList = (MEMORY_BLOCK *)realloc(m_pBlockList, sizeof(MEMORY_BLOCK) * (m_dwNumBlocks + 1));
1293 m_pBlockList[m_dwNumBlocks].pAddr = p;
1294 strcpy(m_pBlockList[m_dwNumBlocks].szFile, file);
1295 m_pBlockList[m_dwNumBlocks].nLine = line;
1296 m_pBlockList[m_dwNumBlocks].nAllocTime = time(NULL);
1297 m_pBlockList[m_dwNumBlocks].nBytes = size;
1298 m_dwNumBlocks++;
1299 }
1300
1301 static void DeleteBlock(void *ptr)
1302 {
1303 DWORD i;
1304
1305 for(i = 0; i < m_dwNumBlocks; i++)
1306 if (m_pBlockList[i].pAddr == ptr)
1307 {
1308 m_dwNumBlocks--;
1309 memmove(&m_pBlockList[i], &m_pBlockList[i + 1], sizeof(MEMORY_BLOCK) * (m_dwNumBlocks - i));
1310 break;
1311 }
1312 }
1313
1314 void *nx_malloc(size_t size, char *file, int line)
1315 {
1316 void *p;
1317
1318 p = malloc(size);
1319 MutexLock(m_mutex, INFINITE);
1320 AddBlock(p, file, line, size);
1321 MutexUnlock(m_mutex);
1322 return p;
1323 }
1324
1325 void *nx_realloc(void *ptr, size_t size, char *file, int line)
1326 {
1327 void *p;
1328
1329 p = realloc(ptr, size);
1330 if (p != ptr)
1331 {
1332 MutexLock(m_mutex, INFINITE);
1333 DeleteBlock(ptr);
1334 AddBlock(p, file, line, size);
1335 MutexUnlock(m_mutex);
1336 }
1337 return p;
1338 }
1339
1340 void nx_free(void *ptr, char *file, int line)
1341 {
1342 free(ptr);
1343 MutexLock(m_mutex, INFINITE);
1344 DeleteBlock(ptr);
1345 MutexUnlock(m_mutex);
1346 }
1347
1348 void PrintMemoryBlocks(void)
1349 {
1350 DWORD i;
1351 LONG nBytes;
1352
1353 MutexLock(m_mutex, INFINITE);
1354 for(i = 0, nBytes = 0; i < m_dwNumBlocks; i++)
1355 {
1356 nBytes += m_pBlockList[i].nBytes;
1357 printf("%08X %d %s:%d (AGE: %d)\n", m_pBlockList[i].pAddr, m_pBlockList[i].nBytes, m_pBlockList[i].szFile, m_pBlockList[i].nLine, m_pBlockList[i].nAllocTime - m_nStartTime);
1358 }
1359 printf("%dK bytes (%d bytes) in %d blocks\n", nBytes / 1024, nBytes, m_dwNumBlocks);
1360 MutexUnlock(m_mutex);
1361 }
1362
1363 #endif
1364
1365
1366 //
1367 // IPSO placeholders
1368 //
1369
1370 #ifdef _IPSO
1371
1372 extern "C" void flockfile(FILE *fp)
1373 {
1374 }
1375
1376 extern "C" void funlockfile(FILE *fp)
1377 {
1378 }
1379
1380 extern "C" int __isthreaded = 1;
1381
1382 #endif
1383
1384
1385 //
1386 // Get memory consumed by current process
1387 //
1388
1389 #ifdef _WIN32
1390
1391 INT64 LIBNETXMS_EXPORTABLE GetProcessRSS()
1392 {
1393 PROCESS_MEMORY_COUNTERS pmc;
1394
1395 if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
1396 return pmc.WorkingSetSize;
1397 return 0;
1398 }
1399
1400 #endif