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