NamedPipe class splitted into NAmedPipe and NamedPipeListener; nxapush switched to...
[public/netxms.git] / src / agent / tools / nxapush / nxapush.cpp
1 /*
2 ** nxapush - command line tool used to push DCI values to NetXMS server
3 ** via local NetXMS agent
4 ** Copyright (C) 2006-2016 Raden Solutions
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 **/
21
22 #include <nms_common.h>
23 #include <nms_agent.h>
24 #include <nms_util.h>
25 #include <nxcpapi.h>
26 #include <nxproc.h>
27
28 #if HAVE_GETOPT_H
29 #include <getopt.h>
30 #endif
31
32 /**
33 * Pipe handle
34 */
35 static NamedPipe *s_pipe = NULL;
36
37 /**
38 * Data to send
39 */
40 static StringMap *s_data = new StringMap;
41
42 /**
43 * options
44 */
45 static int s_optVerbose = 1;
46 static UINT32 s_optObjectId = 0;
47 static time_t s_timestamp = 0;
48
49 /**
50 * Values parser - clean string and split by '='
51 */
52 static BOOL AddValue(TCHAR *pair)
53 {
54 BOOL ret = FALSE;
55 TCHAR *p = pair;
56 TCHAR *value = NULL;
57
58 for (p = pair; *p != 0; p++)
59 {
60 if (*p == _T('=') && value == NULL)
61 {
62 value = p;
63 }
64 if (*p == 0x0D || *p == 0x0A)
65 {
66 *p = 0;
67 break;
68 }
69 }
70
71 if (value != NULL)
72 {
73 *value++ = 0;
74 s_data->set(pair, value);
75 ret = TRUE;
76 }
77
78 return ret;
79 }
80
81 /**
82 * Initialize and connect to the agent
83 */
84 static BOOL Startup()
85 {
86 s_pipe = NamedPipe::connect(_T("nxagentd.push"));
87 if (s_pipe == NULL)
88 return FALSE;
89
90 if (s_optVerbose > 2)
91 _tprintf(_T("Connected to NetXMS agent\n"));
92
93 return TRUE;
94 }
95
96 /**
97 * Send all DCIs
98 */
99 static bool Send()
100 {
101 NXCPMessage msg;
102 msg.setCode(CMD_PUSH_DCI_DATA);
103 msg.setField(VID_OBJECT_ID, s_optObjectId);
104 msg.setFieldFromTime(VID_TIMESTAMP, s_timestamp);
105 s_data->fillMessage(&msg, VID_NUM_ITEMS, VID_PUSH_DCI_DATA_BASE);
106
107 // Send response to pipe
108 NXCP_MESSAGE *rawMsg = msg.createMessage();
109 bool success = s_pipe->write(rawMsg, ntohl(rawMsg->size));
110
111 free(rawMsg);
112 return success;
113 }
114
115 /**
116 * Disconnect and cleanup
117 */
118 static BOOL Teardown()
119 {
120 delete s_pipe;
121 delete s_data;
122 return TRUE;
123 }
124
125 /**
126 * Command line options
127 */
128 #if HAVE_DECL_GETOPT_LONG
129 static struct option longOptions[] =
130 {
131 { (char *)"help", no_argument, NULL, 'h'},
132 { (char *)"object", required_argument, NULL, 'o'},
133 { (char *)"quiet", no_argument, NULL, 'q'},
134 { (char *)"timestamp-unix", required_argument, NULL, 't'},
135 { (char *)"timestamp-text", required_argument, NULL, 'T'},
136 { (char *)"verbose", no_argument, NULL, 'v'},
137 { (char *)"version", no_argument, NULL, 'V'},
138 { NULL, 0, NULL, 0}
139 };
140 #endif
141
142 #define SHORT_OPTIONS "ho:qt:T:vV"
143
144 /**
145 * Show online help
146 */
147 static void usage(char *argv0)
148 {
149 _tprintf(
150 _T("NetXMS Agent PUSH Version ") NETXMS_VERSION_STRING _T("\n")
151 _T("Copyright (c) 2006-2013 Raden Solutions\n\n")
152 _T("Usage: %hs [OPTIONS] [@batch_file] [values]\n")
153 _T(" \n")
154 _T("Options:\n")
155 #if HAVE_GETOPT_LONG
156 _T(" -h, --help Display this help message.\n")
157 _T(" -o, --object <id> Push data on behalf of object with given id.\n")
158 _T(" -q, --quiet Suppress all messages.\n")
159 _T(" -t, --timestamp-unix <time> Specify timestamp for data as UNIX timestamp.\n")
160 _T(" -T, --timestamp-text <time> Specify timestamp for data as YYYYMMDDhhmmss.\n")
161 _T(" -v, --verbose Enable verbose messages. Add twice for debug\n")
162 _T(" -V, --version Display version information.\n\n")
163 #else
164 _T(" -h Display this help message.\n")
165 _T(" -o <id> Push data on behalf of object with given id.\n")
166 _T(" -q Suppress all messages.\n")
167 _T(" -t <time> Specify timestamp for data as UNIX timestamp.\n")
168 _T(" -T <time> Specify timestamp for data as YYYYMMDDhhmmss.\n")
169 _T(" -v Enable verbose messages. Add twice for debug\n")
170 _T(" -V Display version information.\n\n")
171 #endif
172 _T("Notes:\n")
173 _T(" * Values should be given in the following format:\n")
174 _T(" dci=value\n")
175 _T(" where dci can be specified by it's name\n")
176 _T(" * Name of batch file cannot contain character = (equality sign)\n")
177 _T("\n")
178 _T("Examples:\n")
179 _T(" Push two values:\n")
180 _T(" nxapush PushParam1=1 PushParam2=4\n\n")
181 _T(" Push values from file:\n")
182 _T(" nxapush @file\n")
183 , argv0);
184 }
185
186 /**
187 * Entry point
188 */
189 int main(int argc, char *argv[])
190 {
191 int ret = 0;
192 int c;
193
194 InitNetXMSProcess(true);
195
196 opterr = 0;
197 #if HAVE_DECL_GETOPT_LONG
198 while ((c = getopt_long(argc, argv, SHORT_OPTIONS, longOptions, NULL)) != -1)
199 #else
200 while ((c = getopt(argc, argv, SHORT_OPTIONS)) != -1)
201 #endif
202 {
203 switch(c)
204 {
205 case 'h': // help
206 usage(argv[0]);
207 exit(0);
208 break;
209 case 'o': // object ID
210 s_optObjectId = strtoul(optarg, NULL, 0);
211 break;
212 case 'q': // quiet
213 s_optVerbose = 0;
214 break;
215 case 't': // timestamp as UNIX time
216 s_timestamp = (time_t)strtoull(optarg, NULL, 0);
217 break;
218 case 'T': // timestamp as YYYYMMDDhhmmss
219 s_timestamp = ParseDateTimeA(optarg, 0);
220 break;
221 case 'v': // verbose
222 s_optVerbose++;
223 break;
224 case 'V': // version
225 _tprintf(_T("nxapush (") NETXMS_VERSION_STRING _T(")\n"));
226 exit(0);
227 break;
228 case '?':
229 exit(3);
230 break;
231 }
232 }
233
234 if (optind == argc)
235 {
236 if (s_optVerbose > 0)
237 {
238 printf("Not enough arguments\n\n");
239 #if HAVE_GETOPT_LONG
240 printf("Try `%s --help' for more information.\n", argv[0]);
241 #else
242 printf("Try `%s -h' for more information.\n", argv[0]);
243 #endif
244 }
245 exit(1);
246 }
247
248 // Parse
249 if (optind < argc)
250 {
251 while (optind < argc)
252 {
253 char *p = argv[optind];
254
255 if (((*p == '@') && (strchr(p, '=') == NULL)) || (*p == '-'))
256 {
257 FILE *fileHandle = stdin;
258
259 if (*p != '-')
260 {
261 fileHandle = fopen(p + 1, "r");
262 }
263
264 if (fileHandle != NULL)
265 {
266 char buffer[1024];
267
268 while (fgets(buffer, sizeof(buffer), fileHandle) != NULL)
269 {
270 #ifdef UNICODE
271 WCHAR *wvalue = WideStringFromMBString(buffer);
272 AddValue(wvalue);
273 free(wvalue);
274 #else
275 AddValue(buffer);
276 #endif
277 }
278
279 if (fileHandle != stdin)
280 {
281 fclose(fileHandle);
282 }
283 }
284 else
285 {
286 if (s_optVerbose > 0)
287 {
288 printf("Cannot open \"%s\": %s\n", p + 1, strerror(errno));
289 }
290 }
291 }
292 else
293 {
294 #ifdef UNICODE
295 WCHAR *wvalue = WideStringFromMBString(argv[optind]);
296 AddValue(wvalue);
297 free(wvalue);
298 #else
299 AddValue(argv[optind]);
300 #endif
301 }
302
303 optind++;
304 }
305 }
306
307 if (s_data->size() > 0)
308 {
309 if (Startup())
310 {
311 if (Send() != TRUE)
312 {
313 ret = 3;
314 }
315 }
316 }
317 else
318 {
319 if (s_optVerbose > 0)
320 {
321 printf("No valid pairs found; nothing to send\n");
322 ret = 2;
323 }
324 }
325 Teardown();
326
327 return ret;
328 }