0f72835646928c9bc320ce606910cfbbf9054903
[public/netxms.git] / src / agent / subagents / ecs / ecs.cpp
1 /*
2 ** Enhanced CheckSumm subagent
3 ** Copyright (C) 2006-2016 Raden Solutions
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 **/
20
21 #include <nms_common.h>
22 #include <nms_agent.h>
23
24 #ifdef _WIN32
25 #define ECS_EXPORTABLE __declspec(dllexport) __cdecl
26 #else
27 #define ECS_EXPORTABLE
28 #endif
29
30 // max size of remote file (10mb)
31 #define MAX_REMOTE_SIZE (10 * 1024 * 1024)
32
33 static unsigned char *GetHttpUrl(char *url, int *size)
34 {
35 char *ret = NULL;
36
37 char *host = strdup(url);
38
39 char *uri = strchr(host, '/');
40 if (uri == NULL)
41 {
42 uri = (char *)"";
43 }
44 else
45 {
46 *uri = 0;
47 uri++;
48 }
49
50 char *p = strchr(host, ':');
51 unsigned int port = 80;
52 if (p != NULL)
53 {
54 *p = 0;
55 p++;
56 port = atoi(p);
57 if (port == 0)
58 {
59 port = 80;
60 }
61 }
62
63 *size = 0;
64
65 InetAddress hostAddr = InetAddress::resolveHostName(host);
66 if (hostAddr.isValidUnicast() || hostAddr.isLoopback())
67 {
68 SOCKET sd = socket(hostAddr.getFamily(), SOCK_STREAM, 0);
69 if (sd != INVALID_SOCKET)
70 {
71 SockAddrBuffer sa;
72 hostAddr.fillSockAddr(&sa, port);
73 if (ConnectEx(sd, (struct sockaddr *)&sa, SA_LEN((struct sockaddr *)&sa), 5000) == 0)
74 {
75 char req[1024];
76
77 int len = sprintf(req, "GET /%s HTTP/1.0\r\nHost: %s:%u\r\nConnection: close\r\n\r\n", uri, host, port);
78 if (SendEx(sd, req, len, 0, NULL) == len)
79 {
80 char buff[10240];
81 int err;
82 // ok, request sent, read content;
83 while ((err = RecvEx(sd, buff, 10240, 0, 30000)) > 0)
84 {
85 if (*size + err > MAX_REMOTE_SIZE)
86 {
87 free(ret);
88 ret = NULL;
89 break;
90 }
91 p = (char *)realloc(ret, *size + err + 1);
92 if (p != NULL)
93 {
94 ret = p;
95 memcpy(ret + *size, buff, err);
96 *size += err;
97 }
98 else
99 {
100 free(ret);
101 ret = NULL;
102 break;
103 }
104 }
105 }
106 }
107 closesocket(sd);
108 }
109 }
110
111 if (ret != NULL)
112 {
113 if (*size > 7 && !strnicmp(ret, "HTTP/1.", 7))
114 {
115 ret[*size] = 0;
116 char *v1 = strstr(ret, "\r\n\r\n"); // should be this
117 char *v2 = strstr(ret, "\n\n"); // fallback
118
119 p = NULL;
120
121 if (v1 != NULL && v2 == NULL)
122 {
123 p = v1 + 4;
124 }
125 else if (v2 != NULL && v1 == NULL)
126 {
127 p = v2 + 2;
128 }
129 else if (v1 != NULL && v2 != NULL)
130 {
131 p = min(v1 + 4, v2 + 2);
132 }
133
134 if (p != NULL)
135 {
136 *size -= (int)(p - ret);
137 memmove(ret, p, *size);
138 }
139 else
140 {
141 free(ret);
142 ret = NULL;
143 }
144 }
145 else
146 {
147 free(ret);
148 ret = NULL;
149 }
150 }
151
152 free(host);
153 return (unsigned char *)ret;
154 }
155
156 //
157 // Hanlder functions
158 //
159
160 static LONG H_DoHttp(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session)
161 {
162 LONG ret = SYSINFO_RC_ERROR;
163 char szArg[256];
164
165 int digetSize;
166 void (*hashFunction)(const BYTE *, size_t, BYTE *) = NULL;
167 if (CAST_FROM_POINTER(pArg, int) == 1)
168 {
169 digetSize = SHA1_DIGEST_SIZE;
170 hashFunction = CalculateSHA1Hash;
171 }
172 else
173 {
174 digetSize = MD5_DIGEST_SIZE;
175 hashFunction = CalculateMD5Hash;
176 }
177
178 AgentGetParameterArgA(pszParam, 1, szArg, 255);
179
180 if (!strnicmp(szArg, "http://", 7))
181 {
182 int contentSize;
183 unsigned char *content = GetHttpUrl(szArg + 7, &contentSize);
184 if (content != NULL)
185 {
186 unsigned char hash[SHA1_DIGEST_SIZE]; // all hashes should fit (SHA1 == 20, MD5 == 16)
187 hashFunction(content, contentSize, hash);
188
189 char hashText[SHA1_DIGEST_SIZE * 2];
190 for (int i = 0; i < digetSize; i++)
191 {
192 sprintf(hashText + (i * 2), "%02x", hash[i]);
193 }
194
195 ret_mbstring(pValue, hashText);
196 ret = SYSINFO_RC_SUCCESS;
197
198 free(content);
199 }
200 }
201
202 return ret;
203 }
204
205
206 static LONG H_LoadTime(const TCHAR *param, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
207 {
208 LONG ret = SYSINFO_RC_ERROR;
209 char url[256];
210
211 AgentGetParameterArgA(param, 1, url, 255);
212 if (!strnicmp(url, "http://", 7))
213 {
214 int contentSize;
215 INT64 startTime = GetCurrentTimeMs();
216 unsigned char *content = GetHttpUrl(url + 7, &contentSize);
217 if (content != NULL)
218 {
219 DWORD loadTime = (DWORD)(GetCurrentTimeMs() - startTime);
220 ret_uint(value, loadTime);
221 ret = SYSINFO_RC_SUCCESS;
222 free(content);
223 }
224 }
225
226 return ret;
227 }
228
229
230 //
231 // Subagent information
232 //
233
234 static NETXMS_SUBAGENT_PARAM m_parameters[] =
235 {
236 { _T("ECS.HttpSHA1(*)"), H_DoHttp, (TCHAR *)1,
237 DCI_DT_STRING, _T("Calculates SHA1 hash of * URL") },
238 { _T("ECS.HttpMD5(*)"), H_DoHttp, (TCHAR *)5,
239 DCI_DT_STRING, _T("Calculates MD5 hash of * URL") },
240 { _T("ECS.HttpLoadTime(*)"), H_LoadTime, NULL,
241 DCI_DT_STRING, _T("Measure load time for URL *") }
242 };
243
244 static NETXMS_SUBAGENT_INFO m_info =
245 {
246 NETXMS_SUBAGENT_INFO_MAGIC,
247 _T("ECS"), NETXMS_BUILD_TAG,
248 NULL, NULL, NULL,
249 sizeof(m_parameters) / sizeof(NETXMS_SUBAGENT_PARAM),
250 m_parameters,
251 0, NULL, // lists
252 0, NULL, // tables
253 0, NULL, // actions
254 0, NULL // push parameters
255 };
256
257 /**
258 * Entry point for NetXMS agent
259 */
260 DECLARE_SUBAGENT_ENTRY_POINT(ECS)
261 {
262 *ppInfo = &m_info;
263 return TRUE;
264 }
265
266 #ifdef _WIN32
267
268 /**
269 * DLL entry point
270 */
271 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
272 {
273 if (dwReason == DLL_PROCESS_ATTACH)
274 DisableThreadLibraryCalls(hInstance);
275 return TRUE;
276 }
277
278 #endif