- Added component locks
[public/netxms.git] / src / server / core / tools.cpp
CommitLineData
9a19737f
VK
1/*
2** Project X - Network Management System
3** Copyright (C) 2003 Victor Kirhenshtein
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** $module: tools.cpp
20**
21**/
22
23#include "nms_core.h"
24
0ee0c807
VK
25#define PING_SIZE 64
26
27
28//
29// ICMP echo request structure
30//
31
32struct ECHOREQUEST
33{
34 ICMPHDR m_icmpHdr;
35 BYTE m_cData[PING_SIZE];
36};
37
38
39//
40// ICMP echo reply structure
41//
42
43struct ECHOREPLY
44{
45 IPHDR m_ipHdr;
46 ICMPHDR m_icmpHdr;
47 BYTE m_cData[256];
48};
49
9a19737f 50
4385fa12
VK
51//
52// Strip whitespaces and tabs off the string
53//
54
5764fe65 55void StrStrip(char *pStr)
4385fa12
VK
56{
57 int i;
58
5764fe65
VK
59 for(i = 0; (pStr[i] != 0) && ((pStr[i] == ' ') || (pStr[i] == '\t')); i++);
60 if (i > 0)
61 memmove(pStr, &pStr[i], strlen(&pStr[i]) + 1);
62 for(i = strlen(pStr) - 1; (i >= 0) && ((pStr[i] == ' ') || (pStr[i] == '\t')); i--);
63 pStr[i+1] = 0;
4385fa12
VK
64}
65
66
9a19737f
VK
67//
68// Get system error string by call to FormatMessage
69//
70
71#ifdef _WIN32
72
73char *GetSystemErrorText(DWORD error)
74{
75 char *msgBuf;
76 static char staticBuffer[1024];
77
78 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
79 FORMAT_MESSAGE_FROM_SYSTEM |
80 FORMAT_MESSAGE_IGNORE_INSERTS,
81 NULL,error,
82 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), // Default language
83 (LPSTR)&msgBuf,0,NULL)>0)
84 {
85 msgBuf[strcspn(msgBuf,"\r\n")]=0;
86 strncpy(staticBuffer,msgBuf,1023);
87 LocalFree(msgBuf);
88 }
89 else
90 {
91 sprintf(staticBuffer,"MSG 0x%08X - Unable to find message text",error);
92 }
93
94 return staticBuffer;
95}
96
97#endif /* _WIN32 */
0ee0c807
VK
98
99
100//
101// * Checksum routine for Internet Protocol family headers (C Version)
102// *
103// * Author -
104// * Mike Muuss
105// * U. S. Army Ballistic Research Laboratory
106// * December, 1983
107//
108
eefe7d68 109static WORD IPChecksum(WORD *addr, int len)
0ee0c807
VK
110{
111 int nleft = len, sum = 0;
112 WORD *w = addr;
113 WORD answer;
114
115 /*
116 * Our algorithm is simple, using a 32 bit accumulator (sum),
117 * we add sequential 16 bit words to it, and at the end, fold
118 * back all the carry bits from the top 16 bits into the lower
119 * 16 bits.
120 */
121 while(nleft > 1)
122 {
123 sum += *w++;
124 nleft -= 2;
125 }
126
127 /* mop up an odd byte, if necessary */
128 if (nleft == 1)
129 {
130 WORD u = 0;
131
132 *(BYTE *)(&u) = *(BYTE *)w ;
133 sum += u;
134 }
135
136 /*
137 * add back carry outs from top 16 bits to low 16 bits
138 */
139 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
140 sum += (sum >> 16); /* add carry */
141 answer = ~sum; /* truncate to 16 bits */
142 return answer;
143}
144
145
146//
147// Do an ICMP ping to specific address
148// Return value: TRUE if host is alive and FALSE otherwise
149// Parameters: dwAddr - IP address with network byte order
150// iNumRetries - number of retries
151// dwTimeout - Timeout waiting for responce in milliseconds
152//
153
154BOOL IcmpPing(DWORD dwAddr, int iNumRetries, DWORD dwTimeout)
155{
156 SOCKET sock;
157 struct sockaddr_in saDest;
158 BOOL bResult = FALSE;
159 ECHOREQUEST request;
160 ECHOREPLY reply;
87b92f61 161 DWORD dwTimeLeft, dwStartTime, dwElapsedTime;
0ee0c807
VK
162
163 // Create raw socket
164 sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
165 if (sock == -1)
166 {
167 WriteLog(MSG_RAW_SOCK_FAILED, EVENTLOG_ERROR_TYPE, NULL);
168 return FALSE;
169 }
170
171 // Setup destination address structure
172 saDest.sin_addr.s_addr = dwAddr;
173 saDest.sin_family = AF_INET;
174 saDest.sin_port = 0;
175
176 // Fill in request structure
177 request.m_icmpHdr.m_cType = 8; // ICMP ECHO REQUEST
178 request.m_icmpHdr.m_cCode = 0;
179 request.m_icmpHdr.m_wChecksum = 0;
180 request.m_icmpHdr.m_wId = 0x1020;
181 request.m_icmpHdr.m_wSeq = 0;
182
183 // Do ping
87b92f61 184 while(iNumRetries--)
0ee0c807
VK
185 {
186 request.m_icmpHdr.m_wSeq++;
187 request.m_icmpHdr.m_wChecksum = IPChecksum((WORD *)&request, sizeof(ECHOREQUEST));
188 if (sendto(sock, (char *)&request, sizeof(ECHOREQUEST), 0, (struct sockaddr *)&saDest, sizeof(struct sockaddr_in)) == sizeof(ECHOREQUEST))
189 {
190 struct timeval timeout;
191 fd_set rdfs;
192 int iAddrLen;
193 struct sockaddr_in saSrc;
194
195 // Wait for responce
87b92f61 196 for(dwTimeLeft = dwTimeout; dwTimeLeft > 0;)
0ee0c807 197 {
c4495b00
VK
198 FD_ZERO(&rdfs);
199 FD_SET(sock, &rdfs);
87b92f61
VK
200 timeout.tv_sec = dwTimeLeft / 1000;
201 timeout.tv_usec = (dwTimeLeft % 1000) * 1000;
c4495b00
VK
202 dwStartTime = GetTickCount();
203 if (select(sock + 1, &rdfs, NULL, NULL, &timeout) != 0)
204 {
205 dwElapsedTime = GetTickCount() - dwStartTime;
87b92f61 206 dwTimeLeft -= min(dwElapsedTime, dwTimeLeft);
c4495b00
VK
207
208 // Receive reply
209 iAddrLen = sizeof(struct sockaddr_in);
210 if (recvfrom(sock, (char *)&reply, sizeof(ECHOREPLY), 0, (struct sockaddr *)&saSrc, &iAddrLen) > 0)
211 {
c4495b00
VK
212 // Check responce
213 if ((reply.m_ipHdr.m_iaSrc.s_addr == dwAddr) &&
214 (reply.m_icmpHdr.m_cType == 0) &&
215 (reply.m_icmpHdr.m_wId == request.m_icmpHdr.m_wId) &&
216 (reply.m_icmpHdr.m_wSeq == request.m_icmpHdr.m_wSeq))
217 {
218 bResult = TRUE; // We succeed
87b92f61
VK
219 goto stop_ping; // Stop sending packets
220 }
221
222 // Check for "destination unreacheable" error
223 if ((reply.m_icmpHdr.m_cType == 3) &&
224 (reply.m_icmpHdr.m_cCode == 1)) // code 1 is "host unreacheable"
225 {
226 if (((IPHDR *)reply.m_icmpHdr.m_cData)->m_iaDst.S_un.S_addr == dwAddr)
227 goto stop_ping; // Host unreacheable, stop trying
c4495b00 228 }
c4495b00
VK
229 }
230 }
87b92f61 231 else // select() ended on timeout
0ee0c807 232 {
87b92f61 233 dwTimeLeft = 0;
0ee0c807
VK
234 }
235 }
236 }
87b92f61
VK
237
238 ThreadSleepMs(500); // Wait half a second before sending next packet
0ee0c807
VK
239 }
240
87b92f61 241stop_ping:
0ee0c807
VK
242 closesocket(sock);
243 return bResult;
244}
a0495b6e
VK
245
246
48b1c0ac
VK
247//
248// Clean interface list from unneeded entries
249//
250
251void CleanInterfaceList(INTERFACE_LIST *pIfList)
252{
253 int i;
254
255 if (pIfList == NULL)
256 return;
257
258 // Delete loopback interface(s) from list
259 for(i = 0; i < pIfList->iNumEntries; i++)
260 if ((pIfList->pInterfaces[i].dwIpAddr & pIfList->pInterfaces[i].dwIpNetMask) == 0x0000007F)
261 {
262 pIfList->iNumEntries--;
263 memmove(&pIfList->pInterfaces[i], &pIfList->pInterfaces[i + 1],
264 sizeof(INTERFACE_INFO) * (pIfList->iNumEntries - i));
265 i--;
266 }
267}
268
269
a0495b6e
VK
270//
271// Destroy interface list created by discovery functions
272//
273
274void DestroyInterfaceList(INTERFACE_LIST *pIfList)
275{
276 if (pIfList != NULL)
277 {
278 if (pIfList->pInterfaces != NULL)
279 free(pIfList->pInterfaces);
280 free(pIfList);
281 }
282}
ce19c304
VK
283
284
285//
286// Destroy ARP cache created by discovery functions
287//
288
289void DestroyArpCache(ARP_CACHE *pArpCache)
290{
291 if (pArpCache != NULL)
292 {
293 if (pArpCache->pEntries != NULL)
294 free(pArpCache->pEntries);
295 free(pArpCache);
296 }
297}
e77547c2
VK
298
299
300//
0fdc2761 301// Convert byte array to text representation
e77547c2
VK
302//
303
0fdc2761 304void BinToStr(BYTE *pData, DWORD dwSize, char *pStr)
e77547c2 305{
0fdc2761
VK
306 DWORD i;
307 char *pCurr;
308
309 for(i = 0, pCurr = pStr; i < dwSize; i++)
310 {
311 *pCurr++ = bin2hex(pData[i] >> 4);
312 *pCurr++ = bin2hex(pData[i] & 15);
313 }
314 *pCurr = 0;
315}
316
317
318//
319// Convert string of hexadecimal digits to byte array
320//
321
322DWORD StrToBin(char *pStr, BYTE *pData, DWORD dwSize)
323{
324 DWORD i;
e77547c2
VK
325 char *pCurr;
326
0fdc2761
VK
327 memset(pData, 0, dwSize);
328 for(i = 0, pCurr = pStr; (i < dwSize) && (*pCurr != 0); i++)
e77547c2 329 {
0fdc2761 330 pData[i] = hex2bin(*pCurr) << 4;
e77547c2 331 pCurr++;
0fdc2761 332 pData[i] |= hex2bin(*pCurr);
e77547c2
VK
333 pCurr++;
334 }
0fdc2761 335 return i;
e77547c2 336}
c7ca9142
VK
337
338
339//
340// Get system information string
341//
342
343void GetSysInfoStr(char *pszBuffer)
344{
345#ifdef _WIN32
346 DWORD dwSize;
347 char computerName[MAX_COMPUTERNAME_LENGTH + 1], osVersion[256];
348 SYSTEM_INFO sysInfo;
349 OSVERSIONINFO versionInfo;
350
351 dwSize = MAX_COMPUTERNAME_LENGTH + 1;
352 GetComputerName(computerName, &dwSize);
353
354 versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
355 GetVersionEx(&versionInfo);
356 GetSystemInfo(&sysInfo);
357
358 switch(versionInfo.dwPlatformId)
359 {
360 case VER_PLATFORM_WIN32_WINDOWS:
361 sprintf(osVersion,"Windows %s-%s",versionInfo.dwMinorVersion == 0 ? "95" :
362 (versionInfo.dwMinorVersion == 10 ? "98" :
363 (versionInfo.dwMinorVersion == 90 ? "Me" : "Unknown")),versionInfo.szCSDVersion);
364 break;
365 case VER_PLATFORM_WIN32_NT:
366 if (versionInfo.dwMajorVersion != 5)
367 sprintf(osVersion,"Windows NT %d.%d %s",versionInfo.dwMajorVersion,
368 versionInfo.dwMinorVersion,versionInfo.szCSDVersion);
369 else // Windows 2000, Windows XP or Windows Server 2003
370 sprintf(osVersion,"Windows %s%s%s",versionInfo.dwMinorVersion == 0 ? "2000" :
371 (versionInfo.dwMinorVersion == 1 ? "XP" : "Server 2003"),
372 versionInfo.szCSDVersion[0] == 0 ? "" : " ", versionInfo.szCSDVersion);
373 break;
374 default:
375 strcpy(osVersion,"Windows [Unknown Version]");
376 break;
377 }
378
379 sprintf(pszBuffer, "%s %s Build %d", computerName, osVersion, versionInfo.dwBuildNumber);
380#else
381 /* TODO: add UNIX code here */
382#endif
383}
384
385
386//
387// Get IP address for local machine
388//
389
390DWORD GetLocalIpAddr(void)
391{
392 INTERFACE_LIST *pIfList;
393 DWORD dwAddr = 0;
394
395 pIfList = GetLocalInterfaceList();
396 if (pIfList != NULL)
397 {
398 if (pIfList->iNumEntries > 0)
399 dwAddr = pIfList->pInterfaces[0].dwIpAddr;
400 DestroyInterfaceList(pIfList);
401 }
402 return dwAddr;
403}