1 /*----------------------------------------------------------------------------*/
2 /* Xymon demonstration tool.                                                  */
3 /*                                                                            */
4 /* This tool fakes several hosts that can be tested by Xymon, both with       */
5 /* fake network services and fake client data. It is used to demonstrate      */
6 /* features in Xymon.                                                         */
7 /*                                                                            */
8 /* Copyright (C) 2005-2011 Henrik Storner <henrik@hswn.dk>                    */
9 /*                                                                            */
10 /* This program is released under the GNU General Public License (GPL),       */
11 /* version 2. See the file "COPYING" for details.                             */
12 /*                                                                            */
13 /*----------------------------------------------------------------------------*/
14 
15 static char rcsid[] = "$Id: demotool.c 6712 2011-07-31 21:01:52Z storner $";
16 
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/socket.h>
20 #include <limits.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <dirent.h>
26 #include <fcntl.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <sys/time.h>
30 #include <time.h>
31 #include <signal.h>
32 #include <errno.h>
33 #ifdef HAVE_SYS_SELECT_H
34 #include <sys/select.h>
35 #endif
36 
37 char *CONFIGDIR = "/etc/hdemo";
38 struct sockaddr_in srvaddr;
39 volatile int reconfig = 1;
40 
41 typedef struct netsvc_t {
42 	int listenfd;
43 	int delay;
44 	char *response;
45 	int respsize;
46 	struct netsvc_t *next;
47 } netsvc_t;
48 netsvc_t *nethead = NULL;
49 
50 typedef struct active_t {
51 	int fd;
52 	netsvc_t *svc;
53 	struct timeval rbegin;
54 	char *respbuf, *respptr;
55 	int readdone;
56 	int bytesleft;
57 	struct active_t *next;
58 } active_t;
59 active_t *acthead = NULL;
60 
61 typedef struct client_t {
62 	time_t lastupd;
63 	char *hostname;
64 	char *ostype;
65 	time_t bootup;
66 	double minload, maxload;
67 	char *msg;
68 	struct client_t *next;
69 } client_t;
70 client_t *clihead = NULL;
71 
72 static DIR *confdir = NULL;
73 struct dirent *dent = NULL;
74 static char *path = NULL;
75 
nextservice(char * dirname,char * svc)76 char *nextservice(char *dirname, char *svc)
77 {
78 	struct stat st;
79 	char fn[PATH_MAX];
80 	FILE *fd;
81 	char *result;
82 
83 	if (dirname) {
84 		if (confdir) closedir(confdir);
85 		if (path) free(path);
86 		confdir = opendir(dirname);
87 		path = strdup(dirname);
88 	}
89 
90 	do {
91 		do { dent = readdir(confdir); } while (dent && (*(dent->d_name) == '.'));
92 
93 		if (!dent) {
94 			closedir(confdir);
95 			free(path);
96 			path = NULL;
97 			confdir = NULL;
98 			dent = NULL;
99 			return NULL;
100 		}
101 
102 		sprintf(fn, "%s/%s/%s", path, dent->d_name, svc);
103 	} while ( (stat(fn, &st) == -1) || ((fd = fopen(fn, "r")) == NULL) );
104 
105 	result = (char *)malloc(st.st_size+1);
106 	fread(result, 1, st.st_size, fd);
107 	*(result + st.st_size) = '\0';
108 	fclose(fd);
109 
110 	return result;
111 }
112 
svcattrib(char * attr)113 char *svcattrib(char *attr)
114 {
115 	struct stat st;
116 	char fn[PATH_MAX];
117 	FILE *fd;
118 	char *result;
119 
120 	if (!dent) return NULL;
121 
122 	if (!attr) {
123 		sprintf(fn, "%s/%s", path, dent->d_name);
124 		return strdup(fn);
125 	}
126 
127 	sprintf(fn, "%s/%s/%s", path, dent->d_name, attr);
128 	if (stat(fn, &st) == -1) return NULL;
129 	fd = fopen(fn, "r"); if (!fd) return NULL;
130 
131 	result = (char *)calloc(1, st.st_size+1);
132 	fread(result, 1, st.st_size, fd);
133 	fclose(fd);
134 
135 	return result;
136 }
137 
addtobuffer(char ** buf,int * bufsz,char * newtext)138 void addtobuffer(char **buf, int *bufsz, char *newtext)
139 {
140 	if (*buf == NULL) {
141 		*bufsz = strlen(newtext) + 4096;
142 		*buf = (char *) malloc(*bufsz);
143 		**buf = '\0';
144 	}
145 	else if ((strlen(*buf) + strlen(newtext) + 1) > *bufsz) {
146 		*bufsz += strlen(newtext) + 4096;
147 		*buf = (char *) realloc(*buf, *bufsz);
148 	}
149 
150 	strcat(*buf, newtext);
151 }
152 
clientdata(char * cpath)153 char *clientdata(char *cpath)
154 {
155 	char *res = NULL;
156 	int ressz = 0;
157 	DIR *cdir;
158 	struct dirent *d;
159 	char fn[PATH_MAX];
160 	struct stat st;
161 	int n;
162 	FILE *fd;
163 	char buf[4096];
164 
165 	cdir = opendir(cpath);
166 	while ((d = readdir(cdir)) != NULL) {
167 		if (strncmp(d->d_name, "client_", 7) != 0) continue;
168 
169 		sprintf(fn, "%s/%s", cpath, d->d_name);
170 		if (stat(fn, &st) == -1) continue;
171 		fd = fopen(fn, "r"); if (fd == NULL) continue;
172 
173 		sprintf(buf, "[%s]\n", d->d_name+7);
174 		addtobuffer(&res, &ressz, buf);
175 
176 		while ((n = fread(buf, 1, sizeof(buf)-1, fd)) > 0) {
177 			*(buf+n) = '\0';
178 			addtobuffer(&res, &ressz, buf);
179 		}
180 
181 		fclose(fd);
182 	}
183 	closedir(cdir);
184 
185 	if (!res) res = strdup("");
186 
187 	return res;
188 }
189 
timeafter(struct timeval * lim,struct timeval * now)190 int timeafter(struct timeval *lim, struct timeval *now)
191 {
192 	if (now->tv_sec > lim->tv_sec) return 1;
193 	if (now->tv_sec < lim->tv_sec) return 0;
194 	return (now->tv_usec >= lim->tv_usec);
195 }
196 
setuplisteners(void)197 void setuplisteners(void)
198 {
199 	netsvc_t *nwalk;
200 	char *lspec;
201 	struct sockaddr_in laddr;
202 
203 	nwalk = nethead;
204 	while (nwalk) {
205 		netsvc_t *tmp = nwalk;
206 		nwalk = nwalk->next;
207 
208 		if (tmp->listenfd > 0) close(tmp->listenfd);
209 		if (tmp->response) free(tmp->response);
210 		free(tmp);
211 	}
212 	nethead = NULL;
213 
214 	lspec = nextservice(CONFIGDIR, "listen");
215 	while (lspec) {
216 		char *p, *listenip = NULL;
217 		int listenport = -1;
218 		int lsocket, opt;
219 
220 		p = strchr(lspec, ':'); if (p) { *p = '\0'; p++; listenip = lspec; listenport = atoi(p); }
221 
222 		if (listenip && (listenport > 0)) {
223 			memset(&laddr, 0, sizeof(laddr));
224 			inet_aton(listenip, (struct in_addr *) &laddr.sin_addr.s_addr);
225 			laddr.sin_port = htons(listenport);
226 			laddr.sin_family = AF_INET;
227 			lsocket = socket(AF_INET, SOCK_STREAM, 0);
228 
229 			if (lsocket != -1) {
230 				opt = 1;
231 				setsockopt(lsocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
232 				fcntl(lsocket, F_SETFL, O_NONBLOCK);
233 
234 				if ( (bind(lsocket, (struct sockaddr *)&laddr, sizeof(laddr)) != -1) &&
235 				     (listen(lsocket, 10) != -1) ) {
236 					netsvc_t *newitem = malloc(sizeof(netsvc_t));
237 
238 					newitem->listenfd = lsocket;
239 					newitem->response = svcattrib("response");
240 					newitem->respsize = (newitem->response ? strlen(newitem->response) : 0);
241 					p = svcattrib("delay");
242 					newitem->delay = (p ? atoi(p) : 0);
243 					newitem->next = nethead;
244 					nethead = newitem;
245 				}
246 			}
247 		}
248 
249 		free(lspec);
250 		lspec = nextservice(NULL, "listen");
251 	}
252 }
253 
setupclients(void)254 void setupclients(void)
255 {
256 	client_t *cwalk;
257 	char *cspec;
258 
259 	cwalk = clihead;
260 	while (cwalk) {
261 		client_t *tmp = cwalk;
262 		cwalk = cwalk->next;
263 
264 		if (tmp->hostname) free(tmp->hostname);
265 		if (tmp->ostype) free(tmp->ostype);
266 		if (tmp->msg) free(tmp->msg);
267 		free(tmp);
268 	}
269 	clihead = NULL;
270 
271 	cspec = nextservice(CONFIGDIR, "client");
272 	while (cspec) {
273 		char *p;
274 
275 		p = strchr(cspec, ':');
276 		if (p) {
277 			client_t *newitem = (client_t *)malloc(sizeof(client_t));
278 
279 			*p = '\0';
280 			newitem->lastupd = 0;
281 			newitem->hostname = strdup(cspec);
282 			newitem->ostype = strdup(p+1);
283 			while ((p = strchr(newitem->hostname, '.')) != NULL) *p = ',';
284 			p = svcattrib("uptime");
285 			if (p) newitem->bootup = time(NULL) - 60*atoi(p);
286 			else newitem->bootup = time(NULL);
287 			p = svcattrib("minload");
288 			if (p) newitem->minload = atof(p); else newitem->minload = 0.2;
289 			p = svcattrib("maxload");
290 			if (p) newitem->maxload = atof(p); else newitem->maxload = 1.0;
291 			newitem->msg = clientdata(svcattrib(NULL));
292 			newitem->next = clihead;
293 			clihead = newitem;
294 		}
295 
296 		free(cspec);
297 		cspec = nextservice(NULL, "client");
298 	}
299 }
300 
do_select(void)301 void do_select(void)
302 {
303 	fd_set readfds, writefds;
304 	int maxfd, n;
305 	netsvc_t *nwalk;
306 	active_t *awalk, *aprev;
307 	struct timeval now, start;
308 	struct timezone tz;
309 	struct timeval tmo;
310 	char rbuf[4096];
311 
312 	gettimeofday(&start, &tz);
313 	do {
314 		gettimeofday(&now, &tz);
315 		FD_ZERO(&readfds); FD_ZERO(&writefds); maxfd = -1;
316 
317 		nwalk = nethead;
318 		while (nwalk) {
319 			if (nwalk->listenfd) {
320 				FD_SET(nwalk->listenfd, &readfds);
321 				if (nwalk->listenfd > maxfd) maxfd = nwalk->listenfd;
322 			}
323 			nwalk = nwalk->next;
324 		}
325 
326 		awalk = acthead;
327 		while (awalk) {
328 			if (awalk->fd) {
329 				if (!awalk->readdone) {
330 					FD_SET(awalk->fd, &readfds);
331 					if (awalk->fd > maxfd) maxfd = awalk->fd;
332 				}
333 				if (timeafter(&awalk->rbegin, &now)) {
334 					FD_SET(awalk->fd, &writefds);
335 					if (awalk->fd > maxfd) maxfd = awalk->fd;
336 				}
337 			}
338 			awalk = awalk->next;
339 		}
340 
341 		tmo.tv_sec = 0; tmo.tv_usec = 100000;
342 		n = select(maxfd+1, &readfds, &writefds, NULL, &tmo);
343 	} while ((n == 0) && ((now.tv_sec - start.tv_sec) < 10));
344 
345 	if (n <= 0) return;
346 
347 	gettimeofday(&now, &tz);
348 
349 	awalk = acthead; aprev = NULL;
350 	while (awalk) {
351 		if (awalk->fd && !awalk->readdone && FD_ISSET(awalk->fd, &readfds)) {
352 			n = read(awalk->fd, rbuf, sizeof(rbuf));
353 			if (n <= 0) awalk->readdone = 1;
354 		}
355 
356 		if (awalk->fd && awalk->respptr && FD_ISSET(awalk->fd, &writefds)) {
357 			n = write(awalk->fd, awalk->respptr, awalk->bytesleft);
358 			if (n > 0) { awalk->respptr += n; awalk->bytesleft -= n; }
359 		}
360 		else n = 0;
361 
362 		if ((awalk->bytesleft == 0) || (n < 0)) {
363 			if (awalk->respbuf) free(awalk->respbuf);
364 			close(awalk->fd);
365 			awalk->fd = 0;
366 		}
367 
368 		if (awalk->fd) {
369 			aprev = awalk; awalk = awalk->next;
370 		}
371 		else {
372 			active_t *tmp = awalk;
373 
374 			awalk = awalk->next;
375 
376 			if (aprev) aprev->next = awalk;
377 			else acthead = awalk;
378 
379 			free(tmp);
380 		}
381 	}
382 
383 	nwalk = nethead;
384 	while (nwalk) {
385 		int newfd;
386 
387 		if (nwalk->listenfd && FD_ISSET(nwalk->listenfd, &readfds)) {
388 			while ((newfd = accept(nwalk->listenfd, NULL, 0)) > 0) {
389 				/* Pick up a new connection */
390 				fcntl(newfd, F_SETFL, O_NONBLOCK);
391 				active_t *newitem = (active_t *)malloc(sizeof(active_t));
392 				newitem->fd = newfd;
393 				newitem->rbegin.tv_sec = now.tv_sec + nwalk->delay;
394 				newitem->rbegin.tv_usec = now.tv_usec + (random() % 1000000);
395 				if (newitem->rbegin.tv_usec > 1000000) {
396 					newitem->rbegin.tv_usec -= 1000000;
397 					newitem->rbegin.tv_sec++;
398 				}
399 				newitem->svc = nwalk;
400 				if (nwalk->response) {
401 					newitem->respbuf = strdup(nwalk->response);
402 					newitem->respptr = newitem->respbuf;
403 					newitem->bytesleft = nwalk->respsize;
404 				}
405 				else {
406 					newitem->respbuf = NULL;
407 					newitem->respptr = NULL;
408 					newitem->bytesleft = 0;
409 				}
410 				newitem->readdone = 0;
411 				newitem->next = acthead;
412 				acthead = newitem;
413 			}
414 		}
415 		nwalk = nwalk->next;
416 	}
417 }
418 
do_clients(void)419 void do_clients(void)
420 {
421 	client_t *cwalk;
422 	active_t *conn;
423 	time_t now = time(NULL);
424 	time_t uptime;
425 	int updays, uphours, upmins;
426 	int n;
427 	struct tm *tm;
428 	double curload;
429 
430 	cwalk = clihead;
431 	while (cwalk && ((cwalk->lastupd + 60) > now)) cwalk = cwalk->next;
432 	if (!cwalk) return;
433 
434 	cwalk->lastupd = now;
435 	tm = localtime(&now);
436 	uptime = now - cwalk->bootup;
437 	updays = uptime / 86400;
438 	uphours = (uptime % 86400) / 3600;
439 	upmins = (uptime % 3600) / 60;
440 	curload = cwalk->minload + ((random() % 1000) / 1000.0) * (cwalk->maxload - cwalk->minload);
441 
442 	conn = malloc(sizeof(active_t));
443 	conn->fd = socket(AF_INET, SOCK_STREAM, 0);
444 	fcntl(conn->fd, F_SETFL, O_NONBLOCK);
445 	conn->rbegin.tv_sec = now;
446 	conn->rbegin.tv_usec = 0;
447 	conn->svc = NULL;
448 	conn->respbuf = (char *)malloc(strlen(cwalk->msg) + 4096);
449 	sprintf(conn->respbuf, "client %s.%s\n[date]\n%s[uptime]\n %02d:%02d:%02d up %d days, %d:%02d, 1 users, load average: 0.21, %5.2f, 0.25\n\n%s\n",
450 		cwalk->hostname, cwalk->ostype,
451 		ctime(&now),
452 		tm->tm_hour, tm->tm_min, tm->tm_sec,
453 		updays, uphours, upmins,
454 		curload, cwalk->msg);
455 	conn->respptr = conn->respbuf;
456 	conn->bytesleft = strlen(conn->respbuf);
457 	conn->readdone = 0;
458 
459 	n = connect(conn->fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
460 
461 	if ((n == 0) || ((n == -1) && (errno == EINPROGRESS))) {
462 		conn->next = acthead;
463 		acthead = conn;
464 	}
465 	else {
466 		close(conn->fd);
467 		free(conn->respbuf);
468 		free(conn);
469 	}
470 }
471 
sigmisc_handler(int signum)472 void sigmisc_handler(int signum)
473 {
474 	if (signum == SIGHUP) reconfig = 1;
475 }
476 
main(int argc,char * argv[])477 int main(int argc, char *argv[])
478 {
479 	int argi;
480 	struct sigaction sa;
481 	time_t lastconf = 0;
482 
483         memset(&srvaddr, 0, sizeof(srvaddr));
484 	srvaddr.sin_port = htons(1984);
485 	srvaddr.sin_family = AF_INET;
486 	inet_aton("127.0.0.1", (struct in_addr *) &srvaddr.sin_addr.s_addr);
487 
488 	for (argi = 1; (argi < argc); argi++) {
489 		if (strncmp(argv[argi], "--confdir=", 10) == 0) {
490 			char *p = strchr(argv[argi], '=');
491 			CONFIGDIR = strdup(p+1);
492 		}
493 		else if (strncmp(argv[argi], "--srvip=", 8) == 0) {
494 			char *p = strchr(argv[argi], '=');
495 			inet_aton(p+1, (struct in_addr *) &srvaddr.sin_addr.s_addr);
496 		}
497 	}
498 
499 	memset(&sa, 0, sizeof(sa));
500 	sa.sa_handler = sigmisc_handler;
501 	sigaction(SIGHUP, &sa, NULL);
502 
503 	while (1) {
504 		if (reconfig || (time(NULL) > (lastconf+60))) {
505 			printf("(Re)loading config\n");
506 			setuplisteners();
507 			setupclients();
508 			reconfig = 0;
509 			lastconf = time(NULL);
510 		}
511 
512 		do_clients();
513 		do_select();
514 	}
515 
516 	return 0;
517 }
518 
519