1a40be11f9fc2b14b335d0184e80fd73413d4fc3
[public/netxms.git] / src / libnetxms / tools.cpp
1 /* $Id: tools.cpp,v 1.68 2007-09-25 16:53:01 victor Exp $ */
2 /*
3 ** NetXMS - Network Management System
4 ** Copyright (C) 2003, 2004, 2005 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 _stprintf(szBufPtr, _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 (stat(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 if (dwTimeout != INFINITE)
799 {
800 #if HAVE_POLL
801 fds.fd = nSocket;
802 fds.events = POLLIN;
803 fds.revents = POLLIN;
804 do
805 {
806 qwStartTime = GetCurrentTimeMs();
807 iErr = poll(&fds, 1, dwTimeout);
808 if ((iErr != -1) || (errno != EINTR))
809 break;
810 dwElapsed = GetCurrentTimeMs() - qwStartTime;
811 dwTimeout -= min(dwTimeout, dwElapsed);
812 } while(dwTimeout > 0);
813 #else
814 FD_ZERO(&rdfs);
815 FD_SET(nSocket, &rdfs);
816 #ifdef _WIN32
817 tv.tv_sec = dwTimeout / 1000;
818 tv.tv_usec = (dwTimeout % 1000) * 1000;
819 iErr = select(SELECT_NFDS(nSocket + 1), &rdfs, NULL, NULL, &tv);
820 #else
821 do
822 {
823 tv.tv_sec = dwTimeout / 1000;
824 tv.tv_usec = (dwTimeout % 1000) * 1000;
825 qwStartTime = GetCurrentTimeMs();
826 iErr = select(SELECT_NFDS(nSocket + 1), &rdfs, NULL, NULL, &tv);
827 if ((iErr != -1) || (errno != EINTR))
828 break;
829 dwElapsed = GetCurrentTimeMs() - qwStartTime;
830 dwTimeout -= min(dwTimeout, dwElapsed);
831 } while(dwTimeout > 0);
832 #endif
833 #endif
834 if (iErr > 0)
835 {
836 #ifdef _WIN32
837 iErr = recv(nSocket, (char *)pBuff, (int)nSize, nFlags);
838 #else
839 do
840 {
841 iErr = recv(nSocket, (char *)pBuff, nSize, nFlags);
842 } while((iErr == -1) && (errno == EINTR));
843 #endif
844 }
845 else
846 {
847 iErr = -2;
848 }
849 }
850 else
851 {
852 #ifdef _WIN32
853 iErr = recv(nSocket, (char *)pBuff, (int)nSize, nFlags);
854 #else
855 do
856 {
857 iErr = recv(nSocket, (char *)pBuff, nSize, nFlags);
858 } while((iErr == -1) && (errno == EINTR));
859 #endif
860 }
861
862 return iErr;
863 }
864
865
866 //
867 // Resolve host name to IP address
868 //
869
870 DWORD LIBNETXMS_EXPORTABLE ResolveHostName(const TCHAR *pszName)
871 {
872 DWORD dwAddr;
873 struct hostent *hs;
874 #ifdef UNICODE
875 char szBuffer[256];
876
877 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
878 pszName, -1, szBuffer, 256, NULL, NULL);
879 dwAddr = inet_addr(szBuffer);
880 #else
881 dwAddr = inet_addr(pszName);
882 #endif
883 if ((dwAddr == INADDR_NONE) || (dwAddr == INADDR_ANY))
884 {
885 #ifdef UNICODE
886 hs = gethostbyname(szBuffer);
887 #else
888 hs = gethostbyname(pszName);
889 #endif
890 if (hs != NULL)
891 {
892 memcpy(&dwAddr, hs->h_addr, sizeof(DWORD));
893 }
894 else
895 {
896 dwAddr = INADDR_NONE;
897 }
898 }
899
900 return dwAddr;
901 }
902
903
904 #ifndef VER_PLATFORM_WIN32_WINDOWS
905 #define VER_PLATFORM_WIN32_WINDOWS 1
906 #endif
907 #ifndef VER_PLATFORM_WIN32_CE
908 #define VER_PLATFORM_WIN32_CE 3
909 #endif
910
911 //
912 // Get OS name and version
913 //
914
915 void LIBNETXMS_EXPORTABLE GetOSVersionString(TCHAR *pszBuffer, int nBufSize)
916 {
917 int nSize = nBufSize - 1;
918
919 memset(pszBuffer, 0, nBufSize);
920
921 #if defined(_WIN32)
922 OSVERSIONINFO ver;
923
924 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
925 GetVersionEx(&ver);
926 switch(ver.dwPlatformId)
927 {
928 case VER_PLATFORM_WIN32_WINDOWS:
929 _sntprintf(pszBuffer, nSize, _T("Win%s"), ver.dwMinorVersion == 0 ? _T("95") :
930 (ver.dwMinorVersion == 10 ? _T("98") :
931 (ver.dwMinorVersion == 90 ? _T("Me") : _T("9x"))));
932 break;
933 case VER_PLATFORM_WIN32_NT:
934 _sntprintf(pszBuffer, nSize, _T("WinNT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
935 break;
936 #ifdef VER_PLATFORM_WIN32_CE
937 case VER_PLATFORM_WIN32_CE:
938 _sntprintf(pszBuffer, nSize, _T("WinCE %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
939 break;
940 #endif
941 default:
942 _sntprintf(pszBuffer, nSize, _T("WinX %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
943 break;
944 }
945 #elif defined(_NETWARE)
946 struct utsname un;
947
948 uname(&un);
949 _sntprintf(pszBuffer, nSize, _T("NetWare %d.%d"), un.netware_major, un.netware_minor);
950 if (un.servicepack > 0)
951 {
952 int nLen = (int)_tcslen(pszBuffer);
953 nSize -= nLen;
954 if (nSize > 0)
955 _sntprintf(&pszBuffer[nLen], nSize, _T(" sp%d"), un.servicepack);
956 }
957 #else
958 struct utsname un;
959
960 uname(&un);
961 _sntprintf(pszBuffer, nSize, _T("%s %s"), un.sysname, un.release);
962 #endif
963 }
964
965
966 //
967 // Count number of characters in string
968 //
969
970 int LIBNETXMS_EXPORTABLE NumChars(const TCHAR *pszStr, int ch)
971 {
972 const TCHAR *p;
973 int nCount;
974
975 for(p = pszStr, nCount = 0; *p != 0; p++)
976 if (*p == ch)
977 nCount++;
978 return nCount;
979 }
980
981
982 //
983 // Match string against regexp
984 //
985
986 BOOL LIBNETXMS_EXPORTABLE RegexpMatch(TCHAR *pszStr, TCHAR *pszExpr, BOOL bMatchCase)
987 {
988 #ifdef UNICODE
989 regex_t preg;
990 char *mbStr, *mbExpr;
991 BOOL bResult = FALSE;
992
993 mbStr = MBStringFromWideString(pszStr);
994 mbExpr = MBStringFromWideString(pszExpr);
995 if (regcomp(&preg, mbExpr, bMatchCase ? REG_EXTENDED | REG_NOSUB : REG_EXTENDED | REG_NOSUB | REG_ICASE) == 0)
996 {
997 if (regexec(&preg, mbStr, 0, NULL, 0) == 0) // MATCH
998 bResult = TRUE;
999 regfree(&preg);
1000 }
1001 free(mbStr);
1002 free(mbExpr);
1003
1004 return bResult;
1005 #else
1006 regex_t preg;
1007 BOOL bResult = FALSE;
1008
1009 if (regcomp(&preg, pszExpr, bMatchCase ? REG_EXTENDED | REG_NOSUB : REG_EXTENDED | REG_NOSUB | REG_ICASE) == 0)
1010 {
1011 if (regexec(&preg, pszStr, 0, NULL, 0) == 0) // MATCH
1012 bResult = TRUE;
1013 regfree(&preg);
1014 }
1015
1016 return bResult;
1017 #endif
1018 }
1019
1020
1021 //
1022 // Load file into memory
1023 //
1024
1025 #ifndef UNDER_CE
1026
1027 BYTE LIBNETXMS_EXPORTABLE *LoadFile(const TCHAR *pszFileName, DWORD *pdwFileSize)
1028 {
1029 int fd, iBufPos, iNumBytes, iBytesRead;
1030 BYTE *pBuffer = NULL;
1031 struct stat fs;
1032
1033 fd = _topen(pszFileName, O_RDONLY | O_BINARY);
1034 if (fd != -1)
1035 {
1036 if (fstat(fd, &fs) != -1)
1037 {
1038 pBuffer = (BYTE *)malloc(fs.st_size + 1);
1039 if (pBuffer != NULL)
1040 {
1041 *pdwFileSize = fs.st_size;
1042 for(iBufPos = 0; iBufPos < fs.st_size; iBufPos += iBytesRead)
1043 {
1044 iNumBytes = min(16384, fs.st_size - iBufPos);
1045 if ((iBytesRead = read(fd, &pBuffer[iBufPos], iNumBytes)) < 0)
1046 {
1047 free(pBuffer);
1048 pBuffer = NULL;
1049 break;
1050 }
1051 }
1052 }
1053 }
1054 close(fd);
1055 }
1056 return pBuffer;
1057 }
1058
1059 #endif
1060
1061
1062 //
1063 // open/read/write for Windows CE
1064 //
1065
1066 #ifdef UNDER_CE
1067
1068 int LIBNETXMS_EXPORTABLE _topen(TCHAR *pszName, int nFlags, ...)
1069 {
1070 HANDLE hFile;
1071 DWORD dwAccess, dwDisp;
1072
1073 dwAccess = (nFlags & O_RDONLY) ? GENERIC_READ :
1074 (nFlags & O_WRONLY) ? GENERIC_WRITE :
1075 (nFlags & O_RDWR) ? (GENERIC_READ | GENERIC_WRITE) : 0;
1076 if ((nFlags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
1077 dwDisp = CREATE_ALWAYS;
1078 else if ((nFlags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
1079 dwDisp = CREATE_NEW;
1080 else if ((nFlags & O_CREAT) == O_CREAT)
1081 dwDisp = OPEN_ALWAYS;
1082 else if ((nFlags & O_TRUNC) == O_TRUNC)
1083 dwDisp = TRUNCATE_EXISTING;
1084 else
1085 dwDisp = OPEN_EXISTING;
1086 hFile = CreateFile(pszName, dwAccess, FILE_SHARE_READ, NULL, dwDisp,
1087 FILE_ATTRIBUTE_NORMAL, NULL);
1088 return (hFile == INVALID_HANDLE_VALUE) ? -1 : (int)hFile;
1089 }
1090
1091 int LIBNETXMS_EXPORTABLE read(int hFile, void *pBuffer, size_t nBytes)
1092 {
1093 DWORD dwBytes;
1094
1095 if (ReadFile((HANDLE)hFile, pBuffer, nBytes, &dwBytes, NULL))
1096 return dwBytes;
1097 else
1098 return -1;
1099 }
1100
1101 int LIBNETXMS_EXPORTABLE write(int hFile, void *pBuffer, size_t nBytes)
1102 {
1103 DWORD dwBytes;
1104
1105 if (WriteFile((HANDLE)hFile, pBuffer, nBytes, &dwBytes, NULL))
1106 return dwBytes;
1107 else
1108 return -1;
1109 }
1110
1111 #endif /* UNDER_CE */
1112
1113
1114 //
1115 // Memory debugging functions
1116 //
1117
1118 #ifdef NETXMS_MEMORY_DEBUG
1119
1120 #undef malloc
1121 #undef realloc
1122 #undef free
1123
1124 typedef struct
1125 {
1126 void *pAddr;
1127 char szFile[MAX_PATH];
1128 int nLine;
1129 time_t nAllocTime;
1130 LONG nBytes;
1131 } MEMORY_BLOCK;
1132
1133 static MEMORY_BLOCK *m_pBlockList = NULL;
1134 static DWORD m_dwNumBlocks = 0;
1135 static MUTEX m_mutex;
1136 static time_t m_nStartTime;
1137
1138 void InitMemoryDebugger(void)
1139 {
1140 m_mutex = MutexCreate();
1141 m_nStartTime = time(NULL);
1142 }
1143
1144 static void AddBlock(void *p, char *file, int line, size_t size)
1145 {
1146 m_pBlockList = (MEMORY_BLOCK *)realloc(m_pBlockList, sizeof(MEMORY_BLOCK) * (m_dwNumBlocks + 1));
1147 m_pBlockList[m_dwNumBlocks].pAddr = p;
1148 strcpy(m_pBlockList[m_dwNumBlocks].szFile, file);
1149 m_pBlockList[m_dwNumBlocks].nLine = line;
1150 m_pBlockList[m_dwNumBlocks].nAllocTime = time(NULL);
1151 m_pBlockList[m_dwNumBlocks].nBytes = size;
1152 m_dwNumBlocks++;
1153 }
1154
1155 static void DeleteBlock(void *ptr)
1156 {
1157 DWORD i;
1158
1159 for(i = 0; i < m_dwNumBlocks; i++)
1160 if (m_pBlockList[i].pAddr == ptr)
1161 {
1162 m_dwNumBlocks--;
1163 memmove(&m_pBlockList[i], &m_pBlockList[i + 1], sizeof(MEMORY_BLOCK) * (m_dwNumBlocks - i));
1164 break;
1165 }
1166 }
1167
1168 void *nx_malloc(size_t size, char *file, int line)
1169 {
1170 void *p;
1171
1172 p = malloc(size);
1173 MutexLock(m_mutex, INFINITE);
1174 AddBlock(p, file, line, size);
1175 MutexUnlock(m_mutex);
1176 return p;
1177 }
1178
1179 void *nx_realloc(void *ptr, size_t size, char *file, int line)
1180 {
1181 void *p;
1182
1183 p = realloc(ptr, size);
1184 if (p != ptr)
1185 {
1186 MutexLock(m_mutex, INFINITE);
1187 DeleteBlock(ptr);
1188 AddBlock(p, file, line, size);
1189 MutexUnlock(m_mutex);
1190 }
1191 return p;
1192 }
1193
1194 void nx_free(void *ptr, char *file, int line)
1195 {
1196 free(ptr);
1197 MutexLock(m_mutex, INFINITE);
1198 DeleteBlock(ptr);
1199 MutexUnlock(m_mutex);
1200 }
1201
1202 void PrintMemoryBlocks(void)
1203 {
1204 DWORD i;
1205 LONG nBytes;
1206
1207 MutexLock(m_mutex, INFINITE);
1208 for(i = 0, nBytes = 0; i < m_dwNumBlocks; i++)
1209 {
1210 nBytes += m_pBlockList[i].nBytes;
1211 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);
1212 }
1213 printf("%dK bytes (%d bytes) in %d blocks\n", nBytes / 1024, nBytes, m_dwNumBlocks);
1214 MutexUnlock(m_mutex);
1215 }
1216
1217 #endif
1218
1219
1220 //
1221 // IPSO placeholders
1222 //
1223
1224 #ifdef _IPSO
1225
1226 extern "C" void flockfile(FILE *fp)
1227 {
1228 }
1229
1230 extern "C" void funlockfile(FILE *fp)
1231 {
1232 }
1233
1234 extern "C" int __isthreaded = 1;
1235
1236 #endif