2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2015 Victor Kirhenshtein
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published
7 ** by the Free Software Foundation; either version 3 of the License, or
8 ** (at your option) any later version.
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.
15 ** You should have received a copy of the GNU Lesser 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.
23 #include "libnetxms.h"
25 #include <nms_agent.h>
26 #include <nms_threads.h>
27 #include <netxms-regex.h>
34 #define wcsicmp _wcsicmp
37 #if !defined(_WIN32) && !defined(UNDER_CE)
41 #if HAVE_SYS_UTSNAME_H
42 #include <sys/utsname.h>
49 #if HAVE_MALLOC_H && !WITH_JEMALLOC
59 # define EPOCHFILETIME (116444736000000000i64)
61 # define EPOCHFILETIME (116444736000000000LL)
66 * Common initialization for any NetXMS process
68 void LIBNETXMS_EXPORTABLE
InitNetXMSProcess()
72 // Set locale to C. It shouldn't be needed, according to
73 // documentation, but I've seen the cases when agent formats
74 // floating point numbers by sprintf inserting comma in place
75 // of a dot, as set by system's regional settings.
77 setlocale(LC_NUMERIC
, "C");
78 #if defined(UNICODE) && !defined(_WIN32)
79 const char *locale
= getenv("LC_CTYPE");
81 locale
= getenv("LC_ALL");
83 locale
= getenv("LANG");
85 setlocale(LC_CTYPE
, locale
);
89 #ifdef NETXMS_MEMORY_DEBUG
94 SetErrorMode(SEM_FAILCRITICALERRORS
| SEM_NOGPFAULTERRORBOX
| SEM_NOOPENFILEERRORBOX
);
99 * Calculate number of bits in netmask (in host byte order)
101 int LIBNETXMS_EXPORTABLE
BitsInMask(UINT32 dwMask
)
106 for(bits
= 0, dwTemp
= dwMask
; dwTemp
!= 0; bits
++, dwTemp
<<= 1);
111 * Convert IP address from binary form (host bytes order) to string
113 TCHAR LIBNETXMS_EXPORTABLE
*IpToStr(UINT32 dwAddr
, TCHAR
*szBuffer
)
115 static TCHAR szInternalBuffer
[32];
118 szBufPtr
= (szBuffer
== NULL
) ? szInternalBuffer
: szBuffer
;
119 _sntprintf(szBufPtr
, 32, _T("%d.%d.%d.%d"), (int)(dwAddr
>> 24), (int)((dwAddr
>> 16) & 255),
120 (int)((dwAddr
>> 8) & 255), (int)(dwAddr
& 255));
126 char LIBNETXMS_EXPORTABLE
*IpToStrA(UINT32 dwAddr
, char *szBuffer
)
128 static char szInternalBuffer
[32];
131 szBufPtr
= (szBuffer
== NULL
) ? szInternalBuffer
: szBuffer
;
132 snprintf(szBufPtr
, 32, "%d.%d.%d.%d", (int)(dwAddr
>> 24), (int)((dwAddr
>> 16) & 255),
133 (int)((dwAddr
>> 8) & 255), (int)(dwAddr
& 255));
140 * Universal IPv4/IPv6 to string converter
142 TCHAR LIBNETXMS_EXPORTABLE
*SockaddrToStr(struct sockaddr
*addr
, TCHAR
*buffer
)
144 switch(addr
->sa_family
)
147 return IpToStr(ntohl(((struct sockaddr_in
*)addr
)->sin_addr
.s_addr
), buffer
);
149 return Ip6ToStr(((struct sockaddr_in6
*)addr
)->sin6_addr
.s6_addr
, buffer
);
157 * Convert IPv6 address from binary form to string
159 TCHAR LIBNETXMS_EXPORTABLE
*Ip6ToStr(const BYTE
*addr
, TCHAR
*buffer
)
161 static TCHAR internalBuffer
[64];
162 TCHAR
*bufPtr
= (buffer
== NULL
) ? internalBuffer
: buffer
;
164 if (!memcmp(addr
, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
166 _tcscpy(bufPtr
, _T("::"));
171 WORD
*curr
= (WORD
*)addr
;
172 bool hasNulls
= false;
173 for(int i
= 0; i
< 8; i
++)
175 WORD value
= ntohs(*curr
);
176 if ((value
!= 0) || hasNulls
)
180 _sntprintf(out
, 5, _T("%x"), value
);
181 out
= bufPtr
+ _tcslen(bufPtr
);
192 while((*curr
== 0) && (i
< 8));
209 * Convert IPv6 address from binary form to string
211 char LIBNETXMS_EXPORTABLE
*Ip6ToStrA(const BYTE
*addr
, char *buffer
)
213 static char internalBuffer
[64];
214 char *bufPtr
= (buffer
== NULL
) ? internalBuffer
: buffer
;
216 if (!memcmp(addr
, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
218 strcpy(bufPtr
, "::");
223 WORD
*curr
= (WORD
*)addr
;
224 bool hasNulls
= false;
225 for(int i
= 0; i
< 8; i
++)
227 WORD value
= ntohs(*curr
);
228 if ((value
!= 0) || hasNulls
)
232 snprintf(out
, 5, "%x", value
);
233 out
= bufPtr
+ strlen(bufPtr
);
244 while((*curr
== 0) && (i
< 8));
261 * Duplicate memory block
263 void LIBNETXMS_EXPORTABLE
*nx_memdup(const void *data
, size_t size
)
267 newData
= malloc(size
);
268 memcpy(newData
, data
, size
);
273 * Swap two memory blocks
275 void LIBNETXMS_EXPORTABLE
nx_memswap(void *block1
, void *block2
, size_t size
)
280 memcpy(temp
, block1
, size
);
281 memcpy(block1
, block2
, size
);
282 memcpy(block2
, temp
, size
);
286 #if defined(_WIN32) && defined(USE_WIN32_HEAP)
291 char LIBNETXMS_EXPORTABLE
*nx_strdup(const char *src
)
293 return (char *)nx_memdup(src
, strlen(src
) + 1);
299 WCHAR LIBNETXMS_EXPORTABLE
*nx_wcsdup(const WCHAR
*src
)
301 return (WCHAR
*)nx_memdup(src
, (wcslen(src
) + 1) * sizeof(WCHAR
));
306 #if !HAVE_WCSDUP && !defined(_WIN32)
311 WCHAR LIBNETXMS_EXPORTABLE
*wcsdup(const WCHAR
*src
)
313 return (WCHAR
*)nx_memdup(src
, (wcslen(src
) + 1) * sizeof(WCHAR
));
321 WCHAR LIBNETXMS_EXPORTABLE
*nx_wcsdup(const WCHAR
*src
)
323 return (WCHAR
*)nx_memdup(src
, (wcslen(src
) + 1) * sizeof(WCHAR
));
329 * Compare pattern with possible ? characters with given text
331 static bool CompareTextBlocks(const TCHAR
*pattern
, const TCHAR
*text
, size_t size
)
333 const TCHAR
*p
= pattern
;
334 const TCHAR
*t
= text
;
335 for(size_t i
= size
; i
> 0; i
--, p
++, t
++)
346 * Match string against pattern with * and ? metasymbols - implementation
348 static bool MatchStringEngine(const TCHAR
*pattern
, const TCHAR
*string
)
350 const TCHAR
*SPtr
, *MPtr
, *BPtr
, *EPtr
;
373 while(*MPtr
== _T('*'))
377 while(*MPtr
== _T('?')) // Handle "*?" case
385 BPtr
= MPtr
; // Text block begins here
386 while((*MPtr
!= 0) && (*MPtr
!= _T('*')))
387 MPtr
++; // Find the end of text block
388 // Try to find rightmost matching block
389 bsize
= (size_t)(MPtr
- BPtr
);
396 while((*SPtr
!= 0) && (*SPtr
!= *BPtr
))
398 if (_tcslen(SPtr
) < bsize
)
402 return false; // Length of remained text less than remaining pattern
406 SPtr
= EPtr
; // Revert back to point after last match
411 if (CompareTextBlocks(BPtr
, SPtr
, bsize
))
417 EPtr
= SPtr
+ bsize
; // Remember point after last match
418 SPtr
++; // continue scan at next character
441 * Match string against pattern with * and ? metasymbols
443 * @param pattern pattern to match against
444 * @param str string to match
445 * @param matchCase set to true for case-sensetive match
446 * @return true if string matches given pattern
448 bool LIBNETXMS_EXPORTABLE
MatchString(const TCHAR
*pattern
, const TCHAR
*str
, bool matchCase
)
451 return MatchStringEngine(pattern
, str
);
456 tp
= _tcsdup(pattern
);
460 bResult
= MatchStringEngine(tp
, ts
);
467 * Strip whitespaces and tabs off the string
469 void LIBNETXMS_EXPORTABLE
StrStripA(char *str
)
473 for(i
= 0; (str
[i
]!=0) && ((str
[i
] == ' ') || (str
[i
] == '\t')); i
++);
475 memmove(str
, &str
[i
], strlen(&str
[i
]) + 1);
476 for(i
= (int)strlen(str
) - 1; (i
>= 0) && ((str
[i
] == ' ') || (str
[i
] == '\t')); i
--);
481 * Strip whitespaces and tabs off the string
483 void LIBNETXMS_EXPORTABLE
StrStripW(WCHAR
*str
)
487 for(i
= 0; (str
[i
]!=0) && ((str
[i
] == L
' ') || (str
[i
] == L
'\t')); i
++);
489 memmove(str
, &str
[i
], (wcslen(&str
[i
]) + 1) * sizeof(WCHAR
));
490 for(i
= (int)wcslen(str
) - 1; (i
>= 0) && ((str
[i
] == L
' ') || (str
[i
] == L
'\t')); i
--);
495 * Strip whitespaces and tabs off the string.
497 * @param str string to trim
498 * @return str for convenience
500 TCHAR LIBNETXMS_EXPORTABLE
*Trim(TCHAR
*str
)
506 for(i
= 0; (str
[i
] != 0) && _istspace(str
[i
]); i
++);
508 memmove(str
, &str
[i
], (_tcslen(&str
[i
]) + 1) * sizeof(TCHAR
));
509 for(i
= (int)_tcslen(str
) - 1; (i
>= 0) && _istspace(str
[i
]); i
--);
515 * Remove trailing CR/LF or LF from string (multibyte version)
517 void LIBNETXMS_EXPORTABLE
RemoveTrailingCRLFA(char *str
)
522 char *p
= str
+ strlen(str
) - 1;
531 * Remove trailing CR/LF or LF from string (UNICODE version)
533 void LIBNETXMS_EXPORTABLE
RemoveTrailingCRLFW(WCHAR
*str
)
538 WCHAR
*p
= str
+ wcslen(str
) - 1;
547 * Expand file name. Source and destiation may point to same location.
548 * Can be used strftime placeholders and external commands enclosed in ``
550 const TCHAR LIBNETXMS_EXPORTABLE
*ExpandFileName(const TCHAR
*name
, TCHAR
*buffer
, size_t bufSize
, bool allowShellCommands
)
557 TCHAR temp
[8192], command
[1024];
562 ltm
= localtime_r(&t
, &tmBuff
);
566 if (_tcsftime(temp
, 8192, name
, ltm
) <= 0)
569 for(int i
= 0; (temp
[i
] != 0) && (outpos
< bufSize
- 1); i
++)
571 if (temp
[i
] == _T('`') && allowShellCommands
)
574 while((temp
[j
] != _T('`')) && (temp
[j
] != 0))
576 int len
= min(j
- i
, 1023);
577 memcpy(command
, &temp
[i
], len
* sizeof(TCHAR
));
580 FILE *p
= _tpopen(command
, _T("r"));
585 int rc
= (int)fread(result
, 1, 1023, p
);
591 char *lf
= strchr(result
, '\n');
595 len
= (int)min(strlen(result
), bufSize
- outpos
- 1);
597 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, result
, len
, &buffer
[outpos
], len
);
599 memcpy(&buffer
[outpos
], result
, len
);
607 else if (temp
[i
] == _T('$') && temp
[i
+ 1] == _T('{'))
611 while((temp
[j
] != _T('}')) && (temp
[j
] != 0))
614 int len
= min(j
- i
, 1023);
617 memcpy(varName
, &temp
[i
], len
* sizeof(TCHAR
));
620 TCHAR
*result
= _tgetenv(varName
);
623 len
= (int)min(_tcslen(result
), bufSize
- outpos
- 1);
624 memcpy(&buffer
[outpos
], result
, len
* sizeof(TCHAR
));
636 buffer
[outpos
++] = temp
[i
];
647 BOOL LIBNETXMS_EXPORTABLE
CreateFolder(const TCHAR
*directory
)
650 TCHAR
*previous
= _tcsdup(directory
);
651 TCHAR
*ptr
= _tcsrchr(previous
, FS_PATH_SEPARATOR_CHAR
);
656 if (CALL_STAT(previous
, &st
) != 0)
658 result
= CreateFolder(previous
);
661 result
= (CALL_STAT(previous
, &st
) == 0);
666 if (S_ISDIR(st
.st_mode
))
682 result
= CreateDirectory(directory
, NULL
);
684 result
= (_tmkdir(directory
, st
.st_mode
) == 0);
692 * Get current time in milliseconds
693 * Based on timeval.h by Wu Yongwei
695 INT64 LIBNETXMS_EXPORTABLE
GetCurrentTimeMs()
702 GetSystemTimeAsFileTime(&ft
);
703 li
.LowPart
= ft
.dwLowDateTime
;
704 li
.HighPart
= ft
.dwHighDateTime
;
705 t
= li
.QuadPart
; // In 100-nanosecond intervals
706 t
-= EPOCHFILETIME
; // Offset to the Epoch time
707 t
/= 10000; // Convert to milliseconds
712 gettimeofday(&tv
, NULL
);
713 t
= (INT64
)tv
.tv_sec
* 1000 + (INT64
)(tv
.tv_usec
/ 1000);
720 * Extract word from line (UNICODE version). Extracted word will be placed in buffer.
721 * Returns pointer to the next word or to the null character if end
724 const WCHAR LIBNETXMS_EXPORTABLE
*ExtractWordW(const WCHAR
*line
, WCHAR
*buffer
)
729 for(ptr
= line
; (*ptr
== L
' ') || (*ptr
== L
'\t'); ptr
++); // Skip initial spaces
730 // Copy word to buffer
731 for(bptr
= buffer
; (*ptr
!= L
' ') && (*ptr
!= L
'\t') && (*ptr
!= 0); ptr
++, bptr
++)
738 * Extract word from line (multibyte version). Extracted word will be placed in buffer.
739 * Returns pointer to the next word or to the null character if end
742 const char LIBNETXMS_EXPORTABLE
*ExtractWordA(const char *line
, char *buffer
)
747 for(ptr
= line
; (*ptr
== ' ') || (*ptr
== '\t'); ptr
++); // Skip initial spaces
748 // Copy word to buffer
749 for(bptr
= buffer
; (*ptr
!= ' ') && (*ptr
!= '\t') && (*ptr
!= 0); ptr
++, bptr
++)
758 * Get system error string by call to FormatMessage
761 TCHAR LIBNETXMS_EXPORTABLE
*GetSystemErrorText(UINT32 dwError
, TCHAR
*pszBuffer
, size_t iBufSize
)
765 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
766 FORMAT_MESSAGE_FROM_SYSTEM
|
767 FORMAT_MESSAGE_IGNORE_INSERTS
,
769 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), // Default language
770 (LPTSTR
)&msgBuf
, 0, NULL
) > 0)
772 msgBuf
[_tcscspn(msgBuf
, _T("\r\n"))] = 0;
773 nx_strncpy(pszBuffer
, msgBuf
, iBufSize
);
778 _sntprintf(pszBuffer
, iBufSize
, _T("MSG 0x%08X - Unable to find message text"), dwError
);
785 #if (!HAVE_DAEMON || !HAVE_DECL_DAEMON) && !defined(_NETWARE) && !defined(_WIN32)
788 * daemon() implementation for systems which doesn't have one
790 int LIBNETXMS_EXPORTABLE
__daemon(int nochdir
, int noclose
)
794 if ((pid
= fork()) < 0)
797 exit(0); // Terminate parent
806 fclose(stdin
); // don't need stdin, stdout, stderr
817 * Check if given name is a valid object name
819 BOOL LIBNETXMS_EXPORTABLE
IsValidObjectName(const TCHAR
*pszName
, BOOL bExtendedChars
)
821 static TCHAR szValidCharacters
[] = _T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_- @()./");
822 static TCHAR szInvalidCharacters
[] = _T("\x01\x02\x03\x04\x05\x06\x07")
823 _T("\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F")
824 _T("\x10\x11\x12\x13\x14\x15\x16\x17")
825 _T("\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")
826 _T("|\"'*%#\\`;?<>=");
828 return (pszName
[0] != 0) && (bExtendedChars
? (_tcscspn(pszName
, szInvalidCharacters
) == _tcslen(pszName
)) : (_tcsspn(pszName
, szValidCharacters
) == _tcslen(pszName
)));
832 * Check if given name is a valid script name
834 BOOL LIBNETXMS_EXPORTABLE
IsValidScriptName(const TCHAR
*pszName
)
836 static TCHAR szValidCharacters
[] = _T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_:");
837 return (pszName
[0] != 0) && (!isdigit(pszName
[0])) && (pszName
[0] != ':') &&
838 (_tcsspn(pszName
, szValidCharacters
) == _tcslen(pszName
));
842 * Convert 6-byte MAC address to text representation
844 TCHAR LIBNETXMS_EXPORTABLE
*MACToStr(const BYTE
*pData
, TCHAR
*pStr
)
849 for(i
= 0, pCurr
= pStr
; i
< 6; i
++)
851 *pCurr
++ = bin2hex(pData
[i
] >> 4);
852 *pCurr
++ = bin2hex(pData
[i
] & 15);
860 * Convert byte array to text representation (wide character version)
862 WCHAR LIBNETXMS_EXPORTABLE
*BinToStrW(const BYTE
*pData
, size_t size
, WCHAR
*pStr
)
867 for(i
= 0, pCurr
= pStr
; i
< size
; i
++)
869 *pCurr
++ = bin2hex(pData
[i
] >> 4);
870 *pCurr
++ = bin2hex(pData
[i
] & 15);
877 * Convert byte array to text representation (multibyte character version)
879 char LIBNETXMS_EXPORTABLE
*BinToStrA(const BYTE
*pData
, size_t size
, char *pStr
)
884 for(i
= 0, pCurr
= pStr
; i
< size
; i
++)
886 *pCurr
++ = bin2hex(pData
[i
] >> 4);
887 *pCurr
++ = bin2hex(pData
[i
] & 15);
894 * Convert string of hexadecimal digits to byte array (wide character version)
895 * Returns number of bytes written to destination
897 size_t LIBNETXMS_EXPORTABLE
StrToBinW(const WCHAR
*pStr
, BYTE
*pData
, size_t size
)
902 memset(pData
, 0, size
);
903 for(i
= 0, pCurr
= pStr
; (i
< size
) && (*pCurr
!= 0); i
++)
905 pData
[i
] = hex2bin(*pCurr
) << 4;
909 pData
[i
] |= hex2bin(*pCurr
);
917 * Convert string of hexadecimal digits to byte array (multibyte character version)
918 * Returns number of bytes written to destination
920 size_t LIBNETXMS_EXPORTABLE
StrToBinA(const char *pStr
, BYTE
*pData
, size_t size
)
925 memset(pData
, 0, size
);
926 for(i
= 0, pCurr
= pStr
; (i
< size
) && (*pCurr
!= 0); i
++)
928 pData
[i
] = hex2bin(*pCurr
) << 4;
932 pData
[i
] |= hex2bin(*pCurr
);
941 * NOTE: replacement string shouldn't be longer than original
943 void LIBNETXMS_EXPORTABLE
TranslateStr(TCHAR
*pszString
, const TCHAR
*pszSubStr
, const TCHAR
*pszReplace
)
945 TCHAR
*pszSrc
, *pszDst
;
946 int iSrcLen
, iRepLen
;
948 iSrcLen
= (int)_tcslen(pszSubStr
);
949 iRepLen
= (int)_tcslen(pszReplace
);
950 for(pszSrc
= pszString
, pszDst
= pszString
; *pszSrc
!= 0;)
952 if (!_tcsncmp(pszSrc
, pszSubStr
, iSrcLen
))
954 memcpy(pszDst
, pszReplace
, sizeof(TCHAR
) * iRepLen
);
960 *pszDst
++ = *pszSrc
++;
967 * Get size of file in bytes
969 QWORD LIBNETXMS_EXPORTABLE
FileSizeW(const WCHAR
*pszFileName
)
975 struct stat fileInfo
;
979 hFind
= FindFirstFileW(pszFileName
, &fd
);
980 if (hFind
== INVALID_HANDLE_VALUE
)
984 return (unsigned __int64
)fd
.nFileSizeLow
+ ((unsigned __int64
)fd
.nFileSizeHigh
<< 32);
986 if (wstat(pszFileName
, &fileInfo
) == -1)
989 return (QWORD
)fileInfo
.st_size
;
994 * Get size of file in bytes
996 QWORD LIBNETXMS_EXPORTABLE
FileSizeA(const char *pszFileName
)
1000 WIN32_FIND_DATAA fd
;
1002 struct stat fileInfo
;
1006 hFind
= FindFirstFileA(pszFileName
, &fd
);
1007 if (hFind
== INVALID_HANDLE_VALUE
)
1011 return (unsigned __int64
)fd
.nFileSizeLow
+ ((unsigned __int64
)fd
.nFileSizeHigh
<< 32);
1013 if (stat(pszFileName
, &fileInfo
) == -1)
1016 return (QWORD
)fileInfo
.st_size
;
1021 * Get pointer to clean file name (without path specification)
1023 const TCHAR LIBNETXMS_EXPORTABLE
*GetCleanFileName(const TCHAR
*pszFileName
)
1027 ptr
= pszFileName
+ _tcslen(pszFileName
);
1028 while((ptr
>= pszFileName
) && (*ptr
!= _T('/')) && (*ptr
!= _T('\\')) && (*ptr
!= _T(':')))
1034 * Translate DCI data type from text form to code
1036 int LIBNETXMS_EXPORTABLE
NxDCIDataTypeFromText(const TCHAR
*pszText
)
1038 static const TCHAR
*m_pszValidTypes
[] = { _T("INT"), _T("UINT"), _T("INT64"),
1039 _T("UINT64"), _T("STRING"),
1040 _T("FLOAT"), NULL
};
1043 for(i
= 0; m_pszValidTypes
[i
] != NULL
; i
++)
1044 if (!_tcsicmp(pszText
, m_pszValidTypes
[i
]))
1046 return -1; // Invalid data type
1050 * Extended send() - send all data even if single call to send()
1051 * cannot handle them all
1053 int LIBNETXMS_EXPORTABLE
SendEx(SOCKET hSocket
, const void *data
, size_t len
, int flags
, MUTEX mutex
)
1055 int nLeft
= (int)len
;
1065 nRet
= send(hSocket
, ((char *)data
) + (len
- nLeft
), nLeft
, flags
| MSG_NOSIGNAL
);
1067 nRet
= send(hSocket
, ((char *)data
) + (len
- nLeft
), nLeft
, flags
);
1071 if ((WSAGetLastError() == WSAEWOULDBLOCK
)
1073 || (errno
== EAGAIN
)
1077 // Wait until socket becomes available for writing
1084 FD_SET(hSocket
, &wfds
);
1085 nRet
= select(SELECT_NFDS(hSocket
+ 1), NULL
, &wfds
, NULL
, &tv
);
1086 if ((nRet
> 0) || ((nRet
== -1) && (errno
== EINTR
)))
1092 } while (nLeft
> 0);
1097 return nLeft
== 0 ? (int)len
: nRet
;
1101 * Extended recv() - receive data with timeout
1103 * @param hSocket socket handle
1104 * @param data data buffer
1105 * @param len buffer length in bytes
1106 * @param flags flags to be passed to recv() call
1107 * @param timeout waiting timeout in milliseconds
1108 * @return number of bytes read on success, 0 if socket was closed, -1 on error, -2 on timeout
1110 int LIBNETXMS_EXPORTABLE
RecvEx(SOCKET hSocket
, void *data
, size_t len
, int flags
, UINT32 timeout
)
1124 // I've seen on Linux that poll() may hang if fds.fd == -1,
1125 // so we check this ourselves
1126 if (hSocket
== INVALID_SOCKET
)
1129 if (timeout
!= INFINITE
)
1133 fds
.events
= POLLIN
;
1134 fds
.revents
= POLLIN
;
1137 qwStartTime
= GetCurrentTimeMs();
1138 iErr
= poll(&fds
, 1, timeout
);
1139 if ((iErr
!= -1) || (errno
!= EINTR
))
1141 dwElapsed
= GetCurrentTimeMs() - qwStartTime
;
1142 timeout
-= min(timeout
, dwElapsed
);
1143 } while(timeout
> 0);
1146 FD_SET(hSocket
, &rdfs
);
1148 tv
.tv_sec
= timeout
/ 1000;
1149 tv
.tv_usec
= (timeout
% 1000) * 1000;
1150 iErr
= select(SELECT_NFDS(hSocket
+ 1), &rdfs
, NULL
, NULL
, &tv
);
1154 tv
.tv_sec
= timeout
/ 1000;
1155 tv
.tv_usec
= (timeout
% 1000) * 1000;
1156 qwStartTime
= GetCurrentTimeMs();
1157 iErr
= select(SELECT_NFDS(hSocket
+ 1), &rdfs
, NULL
, NULL
, &tv
);
1158 if ((iErr
!= -1) || (errno
!= EINTR
))
1160 dwElapsed
= GetCurrentTimeMs() - qwStartTime
;
1161 timeout
-= min(timeout
, dwElapsed
);
1162 } while(timeout
> 0);
1168 iErr
= recv(hSocket
, (char *)data
, (int)len
, flags
);
1172 iErr
= recv(hSocket
, (char *)data
, len
, flags
);
1173 } while((iErr
== -1) && (errno
== EINTR
));
1184 iErr
= recv(hSocket
, (char *)data
, (int)len
, flags
);
1188 iErr
= recv(hSocket
, (char *)data
, (int)len
, flags
);
1189 } while((iErr
== -1) && (errno
== EINTR
));
1197 * Read exact number of bytes from socket
1199 bool RecvAll(SOCKET s
, void *buffer
, size_t size
, UINT32 timeout
)
1202 char *pos
= (char *)buffer
;
1205 int b
= RecvEx(s
, pos
, size
- bytes
, 0, timeout
);
1215 * Connect with given timeout
1216 * Sets socket to non-blocking mode
1218 int LIBNETXMS_EXPORTABLE
ConnectEx(SOCKET s
, struct sockaddr
*addr
, int len
, UINT32 timeout
)
1220 SetSocketNonBlocking(s
);
1222 int rc
= connect(s
, addr
, len
);
1225 if ((WSAGetLastError() == WSAEWOULDBLOCK
) || (WSAGetLastError() == WSAEINPROGRESS
))
1236 fds
.events
= POLLOUT
;
1237 fds
.revents
= POLLOUT
;
1240 qwStartTime
= GetCurrentTimeMs();
1241 rc
= poll(&fds
, 1, timeout
);
1242 if ((rc
!= -1) || (errno
!= EINTR
))
1244 dwElapsed
= GetCurrentTimeMs() - qwStartTime
;
1245 timeout
-= min(timeout
, dwElapsed
);
1246 } while(timeout
> 0);
1250 if (fds
.revents
== POLLOUT
)
1259 else if (rc
== 0) // timeout, return error
1274 tv
.tv_sec
= timeout
/ 1000;
1275 tv
.tv_usec
= (timeout
% 1000) * 1000;
1276 rc
= select(SELECT_NFDS(s
+ 1), NULL
, &wrfs
, &exfs
, &tv
);
1280 tv
.tv_sec
= timeout
/ 1000;
1281 tv
.tv_usec
= (timeout
% 1000) * 1000;
1282 qwStartTime
= GetCurrentTimeMs();
1283 rc
= select(SELECT_NFDS(s
+ 1), NULL
, &wrfs
, &exfs
, &tv
);
1284 if ((rc
!= -1) || (errno
!= EINTR
))
1286 dwElapsed
= GetCurrentTimeMs() - qwStartTime
;
1287 timeout
-= min(timeout
, dwElapsed
);
1288 } while(timeout
> 0);
1292 if (FD_ISSET(s
, &exfs
))
1295 int err
, len
= sizeof(int);
1296 if (getsockopt(s
, SOL_SOCKET
, SO_ERROR
, (char *)&err
, &len
) == 0)
1297 WSASetLastError(err
);
1306 else if (rc
== 0) // timeout, return error
1310 WSASetLastError(WSAETIMEDOUT
);
1320 * Connect to given host/port
1322 * @return connected socket on success or INVALID_SOCKET on error
1324 SOCKET LIBNETXMS_EXPORTABLE
ConnectToHost(const InetAddress
& addr
, UINT16 port
, UINT32 timeout
)
1326 SOCKET s
= socket(addr
.getFamily(), SOCK_STREAM
, 0);
1327 if (s
== INVALID_SOCKET
)
1328 return INVALID_SOCKET
;
1330 SockAddrBuffer saBuffer
;
1331 struct sockaddr
*sa
= addr
.fillSockAddr(&saBuffer
, port
);
1332 if (ConnectEx(s
, sa
, SA_LEN(sa
), timeout
) == -1)
1341 * Resolve host name to IP address (UNICODE version)
1343 * @param name host name or IP address
1344 * @return IP address in network byte order
1346 UINT32 LIBNETXMS_EXPORTABLE
ResolveHostNameW(const WCHAR
*name
)
1349 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, name
, -1, mbName
, 256, NULL
, NULL
);
1350 return ResolveHostNameA(mbName
);
1354 * Resolve host name to IP address (multibyte version)
1356 * @param name host name or IP address
1357 * @return IP address in network byte order
1359 UINT32 LIBNETXMS_EXPORTABLE
ResolveHostNameA(const char *name
)
1361 UINT32 addr
= inet_addr(name
);
1362 if ((addr
== INADDR_NONE
) || (addr
== INADDR_ANY
))
1364 #if HAVE_GETHOSTBYNAME2_R
1365 struct hostent h
, *hs
= NULL
;
1368 gethostbyname2_r(name
, AF_INET
, &h
, buffer
, 1024, &hs
, &err
);
1370 struct hostent
*hs
= gethostbyname(name
);
1374 memcpy(&addr
, hs
->h_addr
, sizeof(UINT32
));
1385 #ifndef VER_PLATFORM_WIN32_WINDOWS
1386 #define VER_PLATFORM_WIN32_WINDOWS 1
1388 #ifndef VER_PLATFORM_WIN32_CE
1389 #define VER_PLATFORM_WIN32_CE 3
1392 #define SM_SERVERR2 89
1396 * Get OS name and version
1398 void LIBNETXMS_EXPORTABLE
GetOSVersionString(TCHAR
*pszBuffer
, int nBufSize
)
1400 int nSize
= nBufSize
- 1;
1402 memset(pszBuffer
, 0, nBufSize
* sizeof(TCHAR
));
1407 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
1409 switch(ver
.dwPlatformId
)
1411 case VER_PLATFORM_WIN32_WINDOWS
:
1412 _sntprintf(pszBuffer
, nSize
, _T("Win%s"), ver
.dwMinorVersion
== 0 ? _T("95") :
1413 (ver
.dwMinorVersion
== 10 ? _T("98") :
1414 (ver
.dwMinorVersion
== 90 ? _T("Me") : _T("9x"))));
1416 case VER_PLATFORM_WIN32_NT
:
1417 _sntprintf(pszBuffer
, nSize
, _T("WinNT %d.%d"), ver
.dwMajorVersion
, ver
.dwMinorVersion
);
1419 #ifdef VER_PLATFORM_WIN32_CE
1420 case VER_PLATFORM_WIN32_CE
:
1421 _sntprintf(pszBuffer
, nSize
, _T("WinCE %d.%d"), ver
.dwMajorVersion
, ver
.dwMinorVersion
);
1425 _sntprintf(pszBuffer
, nSize
, _T("WinX %d.%d"), ver
.dwMajorVersion
, ver
.dwMinorVersion
);
1428 #elif defined(_NETWARE)
1432 _sntprintf(pszBuffer
, nSize
, _T("NetWare %d.%d"), un
.netware_major
, un
.netware_minor
);
1433 if (un
.servicepack
> 0)
1435 int nLen
= (int)_tcslen(pszBuffer
);
1438 _sntprintf(&pszBuffer
[nLen
], nSize
, _T(" sp%d"), un
.servicepack
);
1446 snprintf(buf
, 1024, "%s %s", un
.sysname
, un
.release
);
1447 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, buf
, -1, pszBuffer
, nSize
);
1449 snprintf(pszBuffer
, nSize
, "%s %s", un
.sysname
, un
.release
);
1457 * Get more specific Windows version string
1459 BOOL LIBNETXMS_EXPORTABLE
GetWindowsVersionString(TCHAR
*versionString
, int strSize
)
1461 OSVERSIONINFOEX ver
;
1464 ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
1465 if (!GetVersionEx((OSVERSIONINFO
*)&ver
))
1468 switch(ver
.dwMajorVersion
)
1471 switch(ver
.dwMinorVersion
)
1474 _tcscpy(buffer
, _T("2000"));
1477 _tcscpy(buffer
, _T("XP"));
1480 _tcscpy(buffer
, (GetSystemMetrics(SM_SERVERR2
) != 0) ? _T("Server 2003 R2") : _T("Server 2003"));
1483 _sntprintf(buffer
, 256, _T("NT %d.%d"), ver
.dwMajorVersion
, ver
.dwMinorVersion
);
1488 switch(ver
.dwMinorVersion
)
1491 _tcscpy(buffer
, (ver
.wProductType
== VER_NT_WORKSTATION
) ? _T("Vista") : _T("Server 2008"));
1494 _tcscpy(buffer
, (ver
.wProductType
== VER_NT_WORKSTATION
) ? _T("7") : _T("Server 2008 R2"));
1497 _tcscpy(buffer
, (ver
.wProductType
== VER_NT_WORKSTATION
) ? _T("8") : _T("Server 2012"));
1500 _tcscpy(buffer
, (ver
.wProductType
== VER_NT_WORKSTATION
) ? _T("8.1") : _T("Server 2012 R2"));
1503 _sntprintf(buffer
, 256, _T("NT %d.%d"), ver
.dwMajorVersion
, ver
.dwMinorVersion
);
1508 switch(ver
.dwMinorVersion
)
1511 _tcscpy(buffer
, (ver
.wProductType
== VER_NT_WORKSTATION
) ? _T("10") : _T("Server"));
1514 _sntprintf(buffer
, 256, _T("NT %d.%d"), ver
.dwMajorVersion
, ver
.dwMinorVersion
);
1519 _sntprintf(buffer
, 256, _T("NT %d.%d"), ver
.dwMajorVersion
, ver
.dwMinorVersion
);
1523 _sntprintf(versionString
, strSize
, _T("Windows %s Build %d %s"), buffer
, ver
.dwBuildNumber
, ver
.szCSDVersion
);
1524 StrStrip(versionString
);
1532 // Count number of characters in string
1535 int LIBNETXMS_EXPORTABLE
NumCharsW(const WCHAR
*pszStr
, WCHAR ch
)
1540 for(p
= pszStr
, nCount
= 0; *p
!= 0; p
++)
1546 int LIBNETXMS_EXPORTABLE
NumCharsA(const char *pszStr
, char ch
)
1551 for(p
= pszStr
, nCount
= 0; *p
!= 0; p
++)
1558 * Match string against regexp (UNICODE version)
1560 BOOL LIBNETXMS_EXPORTABLE
RegexpMatchW(const WCHAR
*str
, const WCHAR
*expr
, bool matchCase
)
1563 bool result
= false;
1565 if (tre_regwcomp(&preg
, expr
, matchCase
? REG_EXTENDED
| REG_NOSUB
: REG_EXTENDED
| REG_NOSUB
| REG_ICASE
) == 0)
1567 if (tre_regwexec(&preg
, str
, 0, NULL
, 0) == 0) // MATCH
1576 * Match string against regexp (multibyte version)
1578 BOOL LIBNETXMS_EXPORTABLE
RegexpMatchA(const char *str
, const char *expr
, bool matchCase
)
1581 bool result
= false;
1583 if (tre_regcomp(&preg
, expr
, matchCase
? REG_EXTENDED
| REG_NOSUB
: REG_EXTENDED
| REG_NOSUB
| REG_ICASE
) == 0)
1585 if (tre_regexec(&preg
, str
, 0, NULL
, 0) == 0) // MATCH
1594 * Translate given code to text
1596 const TCHAR LIBNETXMS_EXPORTABLE
*CodeToText(int iCode
, CODE_TO_TEXT
*pTranslator
, const TCHAR
*pszDefaultText
)
1600 for(i
= 0; pTranslator
[i
].text
!= NULL
; i
++)
1601 if (pTranslator
[i
].code
== iCode
)
1602 return pTranslator
[i
].text
;
1603 return pszDefaultText
;
1607 * Extract option value from string of form option=value;option=value;... (UNICODE version)
1609 bool LIBNETXMS_EXPORTABLE
ExtractNamedOptionValueW(const WCHAR
*optString
, const WCHAR
*option
, WCHAR
*buffer
, int bufSize
)
1612 const WCHAR
*curr
, *start
;
1615 for(curr
= start
= optString
, pos
= 0, state
= 0; *curr
!= 0; curr
++)
1619 case L
';': // Next option
1632 wcsncpy(temp
, start
, curr
- start
);
1633 temp
[curr
- start
] = 0;
1635 if (!wcsicmp(option
, temp
))
1640 else if ((state
== 1) && (pos
< bufSize
- 1))
1642 buffer
[pos
++] = L
'=';
1646 if ((state
== 1) && (pos
< bufSize
- 1))
1647 buffer
[pos
++] = *curr
;
1663 * Extract option value from string of form option=value;option=value;... (multibyte version)
1665 bool LIBNETXMS_EXPORTABLE
ExtractNamedOptionValueA(const char *optString
, const char *option
, char *buffer
, int bufSize
)
1668 const char *curr
, *start
;
1671 for(curr
= start
= optString
, pos
= 0, state
= 0; *curr
!= 0; curr
++)
1675 case ';': // Next option
1688 strncpy(temp
, start
, curr
- start
);
1689 temp
[curr
- start
] = 0;
1691 if (!stricmp(option
, temp
))
1696 else if ((state
== 1) && (pos
< bufSize
- 1))
1698 buffer
[pos
++] = '=';
1702 if ((state
== 1) && (pos
< bufSize
- 1))
1703 buffer
[pos
++] = *curr
;
1719 * Extract named option value as boolean (UNICODE version)
1721 bool LIBNETXMS_EXPORTABLE
ExtractNamedOptionValueAsBoolW(const WCHAR
*optString
, const WCHAR
*option
, bool defVal
)
1724 if (ExtractNamedOptionValueW(optString
, option
, buffer
, 256))
1725 return !wcsicmp(buffer
, L
"yes") || !wcsicmp(buffer
, L
"true");
1730 * Extract named option value as boolean (multibyte version)
1732 bool LIBNETXMS_EXPORTABLE
ExtractNamedOptionValueAsBoolA(const char *optString
, const char *option
, bool defVal
)
1735 if (ExtractNamedOptionValueA(optString
, option
, buffer
, 256))
1736 return !stricmp(buffer
, "yes") || !stricmp(buffer
, "true");
1741 * Extract named option value as integer (UNICODE version)
1743 long LIBNETXMS_EXPORTABLE
ExtractNamedOptionValueAsIntW(const WCHAR
*optString
, const WCHAR
*option
, long defVal
)
1745 WCHAR buffer
[256], *eptr
;
1748 if (ExtractNamedOptionValueW(optString
, option
, buffer
, 256))
1750 val
= wcstol(buffer
, &eptr
, 0);
1758 * Extract named option value as integer (multibyte version)
1760 long LIBNETXMS_EXPORTABLE
ExtractNamedOptionValueAsIntA(const char *optString
, const char *option
, long defVal
)
1762 char buffer
[256], *eptr
;
1765 if (ExtractNamedOptionValueA(optString
, option
, buffer
, 256))
1767 val
= strtol(buffer
, &eptr
, 0);
1777 TCHAR LIBNETXMS_EXPORTABLE
**SplitString(const TCHAR
*source
, TCHAR sep
, int *numStrings
)
1781 *numStrings
= NumChars(source
, sep
) + 1;
1782 strings
= (TCHAR
**)malloc(sizeof(TCHAR
*) * (*numStrings
));
1783 for(int n
= 0, i
= 0; n
< *numStrings
; n
++, i
++)
1786 while((source
[i
] != sep
) && (source
[i
] != 0))
1788 int len
= i
- start
;
1789 strings
[n
] = (TCHAR
*)malloc(sizeof(TCHAR
) * (len
+ 1));
1790 memcpy(strings
[n
], &source
[start
], len
* sizeof(TCHAR
));
1791 strings
[n
][len
] = 0;
1797 * Get step size for "%" and "/" crontab cases
1799 static int GetStepSize(TCHAR
*str
)
1806 step
= *str
== _T('\0') ? 1 : _tcstol(str
, NULL
, 10);
1818 * Get last day of current month
1820 int LIBNETXMS_EXPORTABLE
GetLastMonthDay(struct tm
*currTime
)
1822 switch(currTime
->tm_mon
)
1825 if (((currTime
->tm_year
% 4) == 0) && (((currTime
->tm_year
% 100) != 0) || (((currTime
->tm_year
+ 1900) % 400) == 0)))
1834 case 11: // December
1842 * Match schedule element
1843 * NOTE: We assume that pattern can be modified during processing
1845 bool LIBNETXMS_EXPORTABLE
MatchScheduleElement(TCHAR
*pszPattern
, int nValue
, int maxValue
, struct tm
*localTime
, time_t currTime
)
1848 int nStep
, nCurr
, nPrev
;
1849 bool bRun
= true, bRange
= false;
1851 // Check for "last" pattern
1852 if (*pszPattern
== _T('L'))
1853 return nValue
== maxValue
;
1855 // Check if time() step was specified (% - special syntax)
1856 ptr
= _tcschr(pszPattern
, _T('%'));
1858 return (currTime
% GetStepSize(ptr
)) != 0;
1860 // Check if step was specified
1861 ptr
= _tcschr(pszPattern
, _T('/'));
1862 nStep
= GetStepSize(ptr
);
1864 if (*pszPattern
== _T('*'))
1867 for(curr
= pszPattern
; bRun
; curr
= ptr
+ 1)
1869 for(ptr
= curr
; (*ptr
!= 0) && (*ptr
!= '-') && (*ptr
!= ','); ptr
++);
1874 return false; // Form like 1-2-3 is invalid
1877 nPrev
= _tcstol(curr
, NULL
, 10);
1879 case 'L': // special case for last day ow week in a month (like 5L - last Friday)
1880 if (bRange
|| (localTime
== NULL
))
1881 return false; // Range with L is not supported; nL form supported only for day of week
1883 nCurr
= _tcstol(curr
, NULL
, 10);
1884 if ((nValue
== nCurr
) && (localTime
->tm_mday
+ 7 > GetLastMonthDay(localTime
)))
1895 nCurr
= _tcstol(curr
, NULL
, 10);
1898 if ((nValue
>= nPrev
) && (nValue
<= nCurr
))
1904 if (nValue
== nCurr
)
1914 return (nValue
% nStep
) == 0;
1918 * Failure handler for DecryptPassword
1920 inline bool DecryptPasswordFail(const TCHAR
*encryptedPasswd
, TCHAR
*decryptedPasswd
, size_t bufferLenght
)
1922 if (decryptedPasswd
!= encryptedPasswd
)
1923 nx_strncpy(decryptedPasswd
, encryptedPasswd
, bufferLenght
);
1928 * Decrypt password encrypted with nxencpassw.
1929 * In case when it was not possible to decrypt password as the decrypted password will be set the original one.
1930 * The buffer length for encryptedPasswd and decryptedPasswd should be the same.
1932 bool LIBNETXMS_EXPORTABLE
DecryptPassword(const TCHAR
*login
, const TCHAR
*encryptedPasswd
, TCHAR
*decryptedPasswd
, size_t bufferLenght
)
1934 //check that lenght is correct
1935 if (_tcslen(encryptedPasswd
) != 44)
1936 return DecryptPasswordFail(encryptedPasswd
, decryptedPasswd
, bufferLenght
);
1938 // check that password contains only allowed symbols
1939 int invalidSymbolIndex
= (int)_tcsspn(encryptedPasswd
, _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"));
1940 if ((invalidSymbolIndex
< 42) || ((invalidSymbolIndex
!= 44) && ((encryptedPasswd
[invalidSymbolIndex
] != _T('=')) || ((invalidSymbolIndex
== 42) && (encryptedPasswd
[43] != _T('='))))))
1941 return DecryptPasswordFail(encryptedPasswd
, decryptedPasswd
, bufferLenght
);
1944 char *mbencrypted
= MBStringFromWideString(encryptedPasswd
);
1945 char *mblogin
= MBStringFromWideString(login
);
1947 const char *mbencrypted
= encryptedPasswd
;
1948 const char *mblogin
= login
;
1951 BYTE encrypted
[32], decrypted
[32], key
[16];
1952 size_t encSize
= 32;
1953 base64_decode(mbencrypted
, strlen(mbencrypted
), (char *)encrypted
, &encSize
);
1955 return DecryptPasswordFail(encryptedPasswd
, decryptedPasswd
, bufferLenght
);
1957 CalculateMD5Hash((BYTE
*)mblogin
, strlen(mblogin
), key
);
1958 ICEDecryptData(encrypted
, 32, decrypted
, key
);
1962 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, (char *)decrypted
, -1, decryptedPasswd
, (int)bufferLenght
);
1963 decryptedPasswd
[bufferLenght
- 1] = 0;
1967 nx_strncpy(decryptedPasswd
, (char *)decrypted
, bufferLenght
);
1976 * Load file content into memory
1978 static BYTE
*LoadFileContent(int fd
, UINT32
*pdwFileSize
)
1980 int iBufPos
, iNumBytes
, iBytesRead
;
1981 BYTE
*pBuffer
= NULL
;
1984 if (fstat(fd
, &fs
) != -1)
1986 pBuffer
= (BYTE
*)malloc(fs
.st_size
+ 1);
1987 if (pBuffer
!= NULL
)
1989 *pdwFileSize
= fs
.st_size
;
1990 for(iBufPos
= 0; iBufPos
< fs
.st_size
; iBufPos
+= iBytesRead
)
1992 iNumBytes
= min(16384, fs
.st_size
- iBufPos
);
1993 if ((iBytesRead
= read(fd
, &pBuffer
[iBufPos
], iNumBytes
)) < 0)
2000 if (pBuffer
!= NULL
)
2001 pBuffer
[fs
.st_size
] = 0;
2008 BYTE LIBNETXMS_EXPORTABLE
*LoadFile(const TCHAR
*pszFileName
, UINT32
*pdwFileSize
)
2011 BYTE
*pBuffer
= NULL
;
2013 fd
= _topen(pszFileName
, O_RDONLY
| O_BINARY
);
2016 pBuffer
= LoadFileContent(fd
, pdwFileSize
);
2023 BYTE LIBNETXMS_EXPORTABLE
*LoadFileA(const char *pszFileName
, UINT32
*pdwFileSize
)
2026 BYTE
*pBuffer
= NULL
;
2029 fd
= _open(pszFileName
, O_RDONLY
| O_BINARY
);
2031 fd
= open(pszFileName
, O_RDONLY
| O_BINARY
);
2035 pBuffer
= LoadFileContent(fd
, pdwFileSize
);
2047 * Get memory consumed by current process
2049 INT64 LIBNETXMS_EXPORTABLE
GetProcessRSS()
2051 PROCESS_MEMORY_COUNTERS pmc
;
2053 if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc
, sizeof(pmc
)))
2054 return pmc
.WorkingSetSize
;
2058 #define BG_MASK 0xF0
2059 #define FG_MASK 0x0F
2062 * Apply terminal attributes to console - Win32 API specific
2064 static WORD
ApplyTerminalAttribute(HANDLE out
, WORD currAttr
, long code
)
2066 WORD attr
= currAttr
;
2069 case 0: // reset attribute
2072 case 1: // bold/bright
2073 attr
= currAttr
| FOREGROUND_INTENSITY
;
2075 case 22: // normal color
2076 attr
= currAttr
& ~FOREGROUND_INTENSITY
;
2078 case 30: // black foreground
2079 attr
= (currAttr
& BG_MASK
);
2081 case 31: // red foreground
2082 attr
= (currAttr
& BG_MASK
) | 0x04;
2084 case 32: // green foreground
2085 attr
= (currAttr
& BG_MASK
) | 0x02;
2087 case 33: // yellow foreground
2088 attr
= (currAttr
& BG_MASK
) | 0x06;
2090 case 34: // blue foreground
2091 attr
= (currAttr
& BG_MASK
) | 0x01;
2093 case 35: // magenta foreground
2094 attr
= (currAttr
& BG_MASK
) | 0x05;
2096 case 36: // cyan foreground
2097 attr
= (currAttr
& BG_MASK
) | 0x03;
2099 case 37: // white (gray) foreground
2100 attr
= (currAttr
& BG_MASK
) | 0x07;
2102 case 40: // black background
2103 attr
= (currAttr
& FG_MASK
);
2105 case 41: // red background
2106 attr
= (currAttr
& FG_MASK
) | 0x40;
2108 case 42: // green background
2109 attr
= (currAttr
& FG_MASK
) | 0x20;
2111 case 43: // yellow background
2112 attr
= (currAttr
& FG_MASK
) | 0x60;
2114 case 44: // blue background
2115 attr
= (currAttr
& FG_MASK
) | 0x10;
2117 case 45: // magenta background
2118 attr
= (currAttr
& FG_MASK
) | 0x50;
2120 case 46: // cyan background
2121 attr
= (currAttr
& FG_MASK
) | 0x30;
2123 case 47: // white (gray) background
2124 attr
= (currAttr
& FG_MASK
) | 0x70;
2129 SetConsoleTextAttribute(out
, attr
);
2136 * Write to terminal with support for ANSI color codes
2138 void LIBNETXMS_EXPORTABLE
WriteToTerminal(const TCHAR
*text
)
2141 HANDLE out
= GetStdHandle(STD_OUTPUT_HANDLE
);
2144 if (!GetConsoleMode(out
, &mode
))
2146 // Assume output is redirected
2148 char *mbText
= MBStringFromWideString(text
);
2149 WriteFile(out
, mbText
, (UINT32
)strlen(mbText
), &mode
, NULL
);
2152 WriteFile(out
, text
, (UINT32
)strlen(text
), &mode
, NULL
);
2157 CONSOLE_SCREEN_BUFFER_INFO csbi
;
2158 GetConsoleScreenBufferInfo(out
, &csbi
);
2160 const TCHAR
*curr
= text
;
2163 const TCHAR
*esc
= _tcschr(curr
, 27); // Find ESC
2167 if (*esc
== _T('['))
2169 // write everything up to ESC char
2171 WriteConsole(out
, curr
, (UINT32
)(esc
- curr
- 1), &chars
, NULL
);
2177 while((*esc
!= 0) && (*esc
!= _T('m')))
2179 if (*esc
== _T(';'))
2182 csbi
.wAttributes
= ApplyTerminalAttribute(out
, csbi
.wAttributes
, _tcstol(code
, NULL
, 10));
2195 csbi
.wAttributes
= ApplyTerminalAttribute(out
, csbi
.wAttributes
, _tcstol(code
, NULL
, 10));
2202 WriteConsole(out
, curr
, (UINT32
)(esc
- curr
), &chars
, NULL
);
2209 WriteConsole(out
, curr
, (UINT32
)_tcslen(curr
), &chars
, NULL
);
2216 fputws(text
, stdout
);
2218 char *mbtext
= MBStringFromWideStringSysLocale(text
);
2219 fputs(mbtext
, stdout
);
2223 fputs(text
, stdout
);
2229 * Write to terminal with support for ANSI color codes
2231 void LIBNETXMS_EXPORTABLE
WriteToTerminalEx(const TCHAR
*format
, ...)
2236 va_start(args
, format
);
2237 _vsntprintf(buffer
, 8192, format
, args
);
2239 WriteToTerminal(buffer
);
2243 * mkstemp() implementation for Windows
2247 int LIBNETXMS_EXPORTABLE
mkstemp(char *tmpl
)
2249 char *name
= _mktemp(tmpl
);
2252 return _open(name
, O_RDWR
| O_BINARY
| O_CREAT
| O_EXCL
| _O_SHORT_LIVED
, _S_IREAD
| _S_IWRITE
);
2255 int LIBNETXMS_EXPORTABLE
wmkstemp(WCHAR
*tmpl
)
2257 WCHAR
*name
= _wmktemp(tmpl
);
2260 return _wopen(name
, O_RDWR
| O_BINARY
| O_CREAT
| O_EXCL
| _O_SHORT_LIVED
, _S_IREAD
| _S_IWRITE
);
2268 * strcat_s implementation
2270 int LIBNETXMS_EXPORTABLE
strcat_s(char *dst
, size_t dstSize
, const char *src
)
2272 if (strlen(dst
) + strlen(src
) + 1 >= dstSize
)
2279 * wcscat_s implementation
2281 int LIBNETXMS_EXPORTABLE
wcscat_s(WCHAR
*dst
, size_t dstSize
, const WCHAR
*src
)
2283 if (wcslen(dst
) + wcslen(src
) + 1 >= dstSize
)
2292 * Destructor for RefCountObject
2294 RefCountObject::~RefCountObject()
2299 * Safe _fgetts implementation which will work
2300 * with handles opened by popen
2302 TCHAR LIBNETXMS_EXPORTABLE
*safe_fgetts(TCHAR
*buffer
, int len
, FILE *f
)
2305 #if SAFE_FGETWS_WITH_POPEN
2306 return fgetws(buffer
, len
, f
);
2308 char *mbBuffer
= (char *)alloca(len
);
2309 char *s
= fgets(mbBuffer
, len
, f
);
2312 mbBuffer
[len
- 1] = 0;
2313 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, mbBuffer
, -1, buffer
, len
);
2317 return fgets(buffer
, len
, f
);
2321 #if !HAVE_WCSLWR && !defined(_WIN32)
2324 * Convert UNICODE string to lowercase
2326 WCHAR LIBNETXMS_EXPORTABLE
*wcslwr(WCHAR
*str
)
2328 for(WCHAR
*p
= str
; *p
!= 0; p
++)
2333 if ((*p
>= 'a') && (*p
<= 'z'))
2334 *p
= *p
- ('a' - 'A');
2342 #if !defined(_WIN32) && (!HAVE_WCSFTIME || !WORKING_WCSFTIME)
2345 * wide char version of strftime
2347 size_t LIBNETXMS_EXPORTABLE
nx_wcsftime(WCHAR
*buffer
, size_t bufsize
, const WCHAR
*format
, const struct tm
*t
)
2350 char *mbuf
= (char *)alloca(bufsize
);
2351 size_t flen
= wcslen(format
) + 1;
2352 char *mfmt
= (char *)alloca(flen
);
2353 WideCharToMultiByte(CP_ACP
, WC_DEFAULTCHAR
| WC_COMPOSITECHECK
, format
, -1, mfmt
, flen
, NULL
, NULL
);
2355 char *mbuf
= (char *)malloc(bufsize
);
2356 char *mfmt
= MBStringFromWideString(format
);
2358 size_t rc
= strftime(mbuf
, bufsize
, mfmt
, t
);
2361 MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, mbuf
, -1, buffer
, (int)bufsize
);
2362 buffer
[bufsize
- 1] = 0;
2377 #if !HAVE__ITOA && !defined(_WIN32)
2380 * _itoa() implementation
2382 char LIBNETXMS_EXPORTABLE
*_itoa(int value
, char *str
, int base
)
2395 int rem
= value
% base
;
2396 *t
++ = (rem
< 10) ? (rem
+ '0') : (rem
- 10 + 'a');
2397 value
= value
/ base
;
2409 #if !HAVE__ITOA && !defined(_WIN32)
2412 * _itow() implementation
2414 WCHAR LIBNETXMS_EXPORTABLE
*_itow(int value
, WCHAR
*str
, int base
)
2427 int rem
= value
% base
;
2428 *t
++ = (rem
< 10) ? (rem
+ '0') : (rem
- 10 + 'a');
2429 value
= value
/ base
;
2442 * Get sleep time until specific time
2444 int LIBNETXMS_EXPORTABLE
GetSleepTime(int hour
, int minute
, int second
)
2446 time_t now
= time(NULL
);
2448 struct tm localTime
;
2449 #if HAVE_LOCALTIME_R
2450 localtime_r(&now
, &localTime
);
2452 memcpy(&localTime
, localtime(&now
), sizeof(struct tm
));
2455 int target
= hour
* 3600 + minute
* 60 + second
;
2456 int curr
= localTime
.tm_hour
* 3600 + localTime
.tm_min
* 60 + localTime
.tm_sec
;
2457 return (target
>= curr
) ? target
- curr
: 86400 - (curr
- target
);
2461 * Parse timestamp (should be in form YYMMDDhhmmss or YYYYMMDDhhmmss), local time
2462 * If timestamp string is invalid returns default value
2464 time_t LIBNETXMS_EXPORTABLE
ParseDateTimeA(const char *text
, time_t defaultValue
)
2466 int len
= (int)strlen(text
);
2467 if ((len
!= 12) && (len
!= 14))
2468 return defaultValue
;
2471 char buffer
[16], *curr
;
2473 strncpy(buffer
, text
, 16);
2474 curr
= &buffer
[len
- 2];
2476 memset(&t
, 0, sizeof(struct tm
));
2479 t
.tm_sec
= strtol(curr
, NULL
, 10);
2483 t
.tm_min
= strtol(curr
, NULL
, 10);
2487 t
.tm_hour
= strtol(curr
, NULL
, 10);
2491 t
.tm_mday
= strtol(curr
, NULL
, 10);
2495 t
.tm_mon
= strtol(curr
, NULL
, 10) - 1;
2501 t
.tm_year
= strtol(curr
, NULL
, 10) + 100; // Assuming XXI century
2506 t
.tm_year
= strtol(curr
, NULL
, 10) - 1900;
2513 * Parse timestamp (should be in form YYMMDDhhmmss or YYYYMMDDhhmmss), local time
2514 * If timestamp string is invalid returns default value
2517 time_t LIBNETXMS_EXPORTABLE
ParseDateTimeW(const WCHAR
*text
, time_t defaultValue
)
2520 WideCharToMultiByte(CP_ACP
, WC_COMPOSITECHECK
| WC_DEFAULTCHAR
, text
, -1, buffer
, 16, NULL
, NULL
);
2522 return ParseDateTimeA(buffer
, defaultValue
);
2526 * Get NetXMS directory
2528 void LIBNETXMS_EXPORTABLE
GetNetXMSDirectory(nxDirectoryType type
, TCHAR
*dir
)
2532 const TCHAR
*homeDir
= _tgetenv(_T("NETXMS_HOME"));
2533 if (homeDir
!= NULL
)
2539 _sntprintf(dir
, MAX_PATH
, _T("%s\\bin"), homeDir
);
2542 _sntprintf(dir
, MAX_PATH
, _T("%s\\var"), homeDir
);
2545 _sntprintf(dir
, MAX_PATH
, _T("%s\\etc"), homeDir
);
2548 _sntprintf(dir
, MAX_PATH
, _T("%s\\lib"), homeDir
);
2551 _sntprintf(dir
, MAX_PATH
, _T("%s\\share"), homeDir
);
2554 nx_strncpy(dir
, homeDir
, MAX_PATH
);
2561 _sntprintf(dir
, MAX_PATH
, _T("%s/bin"), homeDir
);
2564 _sntprintf(dir
, MAX_PATH
, _T("%s/var/lib/netxms"), homeDir
);
2567 _sntprintf(dir
, MAX_PATH
, _T("%s/etc"), homeDir
);
2570 _sntprintf(dir
, MAX_PATH
, _T("%s/lib/netxms"), homeDir
);
2573 _sntprintf(dir
, MAX_PATH
, _T("%s/share/netxms"), homeDir
);
2576 nx_strncpy(dir
, homeDir
, MAX_PATH
);
2584 TCHAR installPath
[MAX_PATH
] = _T("");
2587 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, _T("Software\\NetXMS\\Server"), 0, KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
2589 DWORD size
= MAX_PATH
* sizeof(TCHAR
);
2590 found
= (RegQueryValueEx(hKey
, _T("InstallPath"), NULL
, NULL
, (BYTE
*)installPath
, &size
) == ERROR_SUCCESS
);
2596 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, _T("Software\\NetXMS\\Agent"), 0, KEY_QUERY_VALUE
, &hKey
) == ERROR_SUCCESS
)
2598 DWORD size
= MAX_PATH
* sizeof(TCHAR
);
2599 found
= (RegQueryValueEx(hKey
, _T("InstallPath"), NULL
, NULL
, (BYTE
*)installPath
, &size
) == ERROR_SUCCESS
);
2604 if (!found
&& (GetModuleFileName(NULL
, installPath
, MAX_PATH
) > 0))
2606 TCHAR
*p
= _tcsrchr(installPath
, _T('\\'));
2610 p
= _tcsrchr(installPath
, _T('\\'));
2621 _tcscpy(installPath
, _T("C:\\NetXMS"));
2627 _sntprintf(dir
, MAX_PATH
, _T("%s\\bin"), installPath
);
2630 _sntprintf(dir
, MAX_PATH
, _T("%s\\var"), installPath
);
2633 _sntprintf(dir
, MAX_PATH
, _T("%s\\etc"), installPath
);
2636 _sntprintf(dir
, MAX_PATH
, _T("%s\\lib"), installPath
);
2639 _sntprintf(dir
, MAX_PATH
, _T("%s\\share"), installPath
);
2642 nx_strncpy(dir
, installPath
, MAX_PATH
);
2650 _tcscpy(dir
, PREFIX
_T("/bin"));
2652 _tcscpy(dir
, _T("/usr/bin"));
2657 _tcscpy(dir
, STATEDIR
);
2659 _tcscpy(dir
, _T("/var/lib/netxms"));
2664 _tcscpy(dir
, PREFIX
_T("/etc"));
2666 _tcscpy(dir
, _T("/etc"));
2671 _tcscpy(dir
, PKGLIBDIR
);
2673 _tcscpy(dir
, _T("/usr/lib/netxms"));
2678 _tcscpy(dir
, DATADIR
);
2680 _tcscpy(dir
, _T("/usr/share/netxms"));
2684 _tcscpy(dir
, _T("/usr"));
2693 * Callback for jemalloc's malloc_stats_print
2695 static void jemalloc_stats_cb(void *arg
, const char *text
)
2697 fwrite(text
, 1, strlen(text
), (FILE *)arg
);
2703 * Get heap information using system-specific functions (if available)
2705 TCHAR LIBNETXMS_EXPORTABLE
*GetHeapInfo()
2707 #if WITH_JEMALLOC || HAVE_MALLOC_INFO
2708 char *buffer
= NULL
;
2710 FILE *f
= open_memstream(&buffer
, &size
);
2714 malloc_stats_print(jemalloc_stats_cb
, f
, NULL
);
2720 WCHAR
*wtext
= WideStringFromMBString(buffer
);
2727 return _tcsdup(_T("No heap information API available"));
2732 * Destructor for abstract iterator
2734 AbstractIterator::~AbstractIterator()
2739 * Escape string for JSON
2741 String LIBNETXMS_EXPORTABLE
EscapeStringForJSON(const TCHAR
*s
)
2746 for(const TCHAR
*p
= s
; *p
!= 0; p
++)
2748 if (*p
== _T('"') || *p
== _T('\\'))
2749 js
.append(_T('\\'));
2756 * Escape string for agent parameter
2758 String LIBNETXMS_EXPORTABLE
EscapeStringForAgent(const TCHAR
*s
)
2763 for(const TCHAR
*p
= s
; *p
!= 0; p
++)
2766 out
.append(_T('"'));