/* udpserver.c
 * $Id: udpserver.c,v 1.3.2.4 2005/08/03 13:44:15 becker Exp $
 * Ralf Becker <nctop@web.de>
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include <sysexits.h>

#ifdef HAVE_LWRAP
#include <syslog.h>
#ifdef HAVE_TCPD_H
#include <tcpd.h>
#endif /* HAVE_TCPD_H */
#endif /* HAVE_LWRAP */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "machine.h"
#include "udpserver.h"
 
#define MAXMSGLEN  4096

static char cvsid[] = "$Id: udpserver.c,v 1.3.2.4 2005/08/03 13:44:15 becker Exp $";

#define HOSTSTAT  1
#define SWAPSTAT  2
#define LOADAVG   3
#define CPUSTAT   4
#define MEMSTAT   5
#define PROCTABLE 6

typedef struct {
	char *name;
	int token;
} requesttype;

int buferr;

requesttype requests[] = {
	{ "LOADAVG",   LOADAVG },
	{ "CPUSTAT",   CPUSTAT },
	{ "SWAPSTAT",  SWAPSTAT },
	{ "MEMSTAT",   MEMSTAT },
	{ "HOSTSTAT",  HOSTSTAT },
	{ NULL, 0 }
};

#ifdef HAVE_TCPD_H
int deny_severity = LOG_INFO;
int allow_severity = LOG_INFO;
#endif /* HAVE_TCPD_H */

int mysnprintf(char *buf, int buflen, char *fmt, ...) {

	va_list args;
	int len;

	buferr = 0;
	va_start(args,fmt);
	if ((len = vsnprintf(buf, buflen, fmt, args)) > buflen) {
		fprintf (stderr,"%s: internal buffer too small\n",myname);
		buferr = 1;
		return buflen;
	}
	va_end(args);
	return len;
	
}
	
int print_MEMSTAT(char *buf,int buflen) {

	int i;
	int len;

	len = mysnprintf(buf, buflen, "mem: ");
	for (i=0; i < MEMSTATS-1; i++) {
		len += mysnprintf(&buf[len], buflen-len, "%s %u, ",
			mem_names[i],hoststat.mem[i]);
	}
	len += mysnprintf(&(buf[len]), buflen-len, "%s %u, \n",
			mem_names[i],hoststat.mem[i]);
	return len;
}

int print_SWAPSTAT(char *buf,int buflen) {

	int i;
	int len;

	len = mysnprintf(buf, buflen, "swap: ");
	for (i=0; i < SWAPSTATS-1; i++) {
		len += mysnprintf(&(buf[len]), buflen-len, "%s %u, ",
			swap_names[i],hoststat.swap[i]);
	}
	len += mysnprintf(&(buf[len]), buflen-len, "%s %u, \n",
			swap_names[i],hoststat.swap[i]);
	return len;
}

int print_CPUSTAT(char *buf,int buflen) {

	int i;
	int len;

	len = mysnprintf(buf, buflen, "CPU states: ");
	for (i=0; i < CPUSTATS-1; i++) {
		len += mysnprintf(&(buf[len]), buflen-len, "%3u%% %s, ",
			hoststat.cpu[i],cpu_names[i]);
	}
	len += mysnprintf(&(buf[len]), buflen-len, "%3u%% %s\n",
		hoststat.cpu[i],cpu_names[i]);
	return len;
}


int print_LOADAVG(char *buf, int buflen)  {

	int i;
	int len;

	len = mysnprintf(buf, buflen, "load averages: ");
	for (i=0; i < LOADAVGS-1; i++) {
		len += mysnprintf(&(buf[len]), buflen-len, "%.2f, ",
			(double)hoststat.loadavg[i]);
	}
	len += mysnprintf(&(buf[len]), buflen-len, "%.2f\n",
		(double)hoststat.loadavg[i]);
	return len;
}

int print_NUSERS(char *buf, int buflen)  {

	int len;

	len = mysnprintf(buf, buflen, "nusers: ");
	len += mysnprintf(&(buf[len]), buflen-len, "%3u\n",
		hoststat.nusers);
	return len;
}


int print_HOSTSTAT(char *buf, int buflen) {

	int len;

	len = print_LOADAVG(buf,buflen);
	len += print_CPUSTAT(&(buf[len]), buflen-len);
	len += print_MEMSTAT(&(buf[len]), buflen-len);
	len += print_SWAPSTAT(&(buf[len]), buflen-len);
	len += print_NUSERS(&(buf[len]), buflen-len);
	return len;
}

/* check if this a valid request */
int checkrequest(char *req) {

	requesttype *p;

	for (p = requests; p->name != NULL; p++) {
		if (strncmp(p->name, req, MAXMSGLEN) == 0) {
			return p->token;
		}
	}

	return -1;
}

/* answer the request msg */
int answerrequest(int sockfd, char *req, struct sockaddr_in hisaddr) {

	int request;
	char msg[MAXMSGLEN];
	int msglen;
	int hisaddrlen;

	if ((request = checkrequest(req)) == -1) {
		fprintf (stderr,"invalid request %s from %s\n",
				req, inet_ntoa(hisaddr.sin_addr));
		return(-1);
	}
	msglen = 0;
	switch (request) {
		case HOSTSTAT: {
			msglen = print_HOSTSTAT(msg, MAXMSGLEN);
			break;
		}
		case MEMSTAT: {
			msglen = print_MEMSTAT(msg, MAXMSGLEN);
			break;
		}
		case SWAPSTAT: {
			msglen = print_SWAPSTAT(msg, MAXMSGLEN);
			break;
		}
		case CPUSTAT: {
			msglen=print_CPUSTAT(msg,MAXMSGLEN);
			break;
		}
		case LOADAVG: {
			msglen=print_LOADAVG(msg,MAXMSGLEN);
			break;
		}
		default: {
			 fprintf (stderr,\
				"%s: valid request %s with no definition\n",
				myname, msg);
		}
	}

	hisaddrlen = sizeof(struct sockaddr);
	if (buferr) {
		msg[0] = '\0';
	}
	if ((msglen = sendto(sockfd, msg, MAXMSGLEN , 0,
		(struct sockaddr *)&hisaddr, hisaddrlen)) < 0) {
		perror(myname);
		exit(EX_IOERR);
	}
	
	return(0);
}

/* handle the network section
 * open port on port
 */
int udpserver(int port) {

#ifdef HAVE_LWRAP
	/* data for tcpwrapper */
	struct request_info request;
#endif /* HAVE_LWRAP */

	/* adress information for local, remote address */
	struct sockaddr_in myaddr;
	struct sockaddr_in hisaddr;
	int hisaddrlen;

	int sockfd;

	char msg[MAXMSGLEN];
	int  msglen; 	/* the length of the received message */

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror(myname);
		return(EX_UNAVAILABLE);
	}

	bzero(&myaddr, sizeof(struct sockaddr_in)); /* zero the structure */
	myaddr.sin_family = AF_INET;
	myaddr.sin_port = htons(port);   /* the port in network byte order */
	myaddr.sin_addr.s_addr = INADDR_ANY; 

	/* bind to the port */
	if (bind(sockfd, (struct sockaddr *)&myaddr, \
		sizeof(struct sockaddr)) == -1) {
		perror(myname);
		close(sockfd);
		return(EX_UNAVAILABLE);
	}
#ifdef HAVE_LWRAP
	/* initialize request structure */
	request_init(&request, RQ_DAEMON, "nctopd", RQ_FILE, sockfd, 
		RQ_SERVER_SIN, &myaddr, 0);
#endif /* HAVE_LWRAP */

	while (1) {
		/* check for incoming messages */
		hisaddrlen = sizeof(struct sockaddr);
		if ((msglen = recvfrom(sockfd, msg, MAXMSGLEN-1, 0, \
			(struct sockaddr *)&hisaddr, &hisaddrlen)) < 0) {
			perror(myname);
			continue;
		} 
#ifdef HAVE_LWRAP
		/* check with libwrap */
		request_set(&request, RQ_CLIENT_SIN, &hisaddr, 0);
		fromhost(&request);

		if (hosts_access(&request) == 0) {
		/*
			fprintf(stderr, "access denied from %s\n", 
				inet_ntoa(hisaddr.sin_addr));
		 */
			continue;
		}
#endif /* HAVE_LWRAP */
		/* answer the request */
		msg[msglen] = '\0';
		/*
		printf("message received from %s: %s\n", \
			inet_ntoa(hisaddr.sin_addr),msg); 
		*/
		answerrequest(sockfd, msg, hisaddr);
	}
			
	return(0); /* never reached */
}


syntax highlighted by Code2HTML, v. 0.9.1