--- projects/cms/source/ihost/ihost.c 2002/05/18 18:15:56 1.11 +++ projects/cms/source/ihost/ihost.c 2003/03/04 10:44:36 1.31 @@ -1,5 +1,6 @@ /* * i-scream central monitoring system + * http://www.i-scream.org.uk * Copyright (C) 2000-2002 i-scream * * This program is free software; you can redistribute it and/or @@ -17,450 +18,797 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include -#include #include #include -#include -#include -#include "ukcprog.h" +#include +#include +#include +#include +#include #include -#include + +#include "ukcprog.h" #include "statgrab.h" -#define RECONFIGURE_RETURN_CODE 2 -#define UDP_MAX_PACKET_SIZE 8192 +#define LOG_CRIT 0 +#define LOG_ERR 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 typedef struct{ - int fm_port; - char *fm_host; - - char *my_fqdn; + int filtermanager_port; + char *filtermanager_host; + + char *host_ip; + char *host_fqdn; + char *server_fqdn; int server_udp_port; - int server_tcp_port; + + /* Weird stuff iscream wants sent to it */ char *last_modified; - char *files_list; - char *key; + char *file_list; + int udp_update_time; - int tcp_update_time; +// int config_ttl; + time_t config_ttl; + }ihost_state_t; -char* sock_comm(FILE *f_r, FILE *f_w, char *sendString){ - char *reply; - fprintf(f_w, "%s\n", sendString); - fflush(f_w); - reply=fpgetline(f_r); - /* Returns pointer to static buffer */ - return reply; -} +typedef struct{ + int verbose; + int daemon; -int ihost_configure(ihost_state_t *ihost_state){ + FILE *log; +}ihost_config_t; + +typedef struct{ struct sockaddr_in addr; - struct in_addr haddr; - int sd; - FILE *fm_fd_r, *fm_fd_w; - char *reply; - char *reply_ptr; + int sock; +}udp_sockinfo_t; - /* Check to see if anything needs to be free'd */ - if (ihost_state->my_fqdn!=NULL) free(ihost_state->my_fqdn); - if (ihost_state->server_fqdn!=NULL) free(ihost_state->server_fqdn); - if (ihost_state->last_modified!=NULL) free(ihost_state->last_modified); - if (ihost_state->files_list!=NULL) free(ihost_state->files_list); +ihost_config_t ihost_config; - if ((sd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { - errf("Can't create AF_INET socket (%m)"); - return -1; - } +void log_msg(int level, char *format, ...){ + extern int errno; + int cur_errno; + va_list ap; - if (get_host_addr(ihost_state->fm_host, &haddr) != 0){ - errf("Failed to resolve address %s (%m)", ihost_state->fm_host); - return -1; + cur_errno=errno; + + if(level<=ihost_config.verbose){ + va_start(ap, format); + vfprintf(ihost_config.log, format, ap); + va_end(ap); + if(level==LOG_CRIT){ + fprintf(ihost_config.log, " (%s)\n", strerror(cur_errno)); + }else{ + fprintf(ihost_config.log, "\n"); + } } +} - memset(&addr, 0, sizeof addr); - addr.sin_family = AF_INET; - memcpy(&addr.sin_addr, &haddr, sizeof haddr); - addr.sin_port = htons(ihost_state->fm_port); +/* Takes many pointers, checks if they are NULL or not, and then free's them */ +/* Deprciated - and i only wrote it today! :) +void m_free(int num_pointers, ...){ + int x=0; + va_list ap; + void *p; - if (connect(sd, (struct sockaddr *)&addr, sizeof addr) != 0) { - errf("Failed to connect to %s on port %d (%m)", ihost_state->fm_host, ihost_state->fm_port); - return -1; + va_start(ap, num_pointers); + for(;xsock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){ + log_msg(LOG_CRIT, "Failed to create UDP socket"); + return 1; } - reply=sock_comm(fm_fd_r, fm_fd_w, "STARTCONFIG"); - if ((reply==NULL) || (strncasecmp(reply, "OK", 2) != 0) ) { - errf("Server error"); - return -1; + memset(&(udp_sockinfo->addr), 0, sizeof(struct sockaddr_in)); + udp_sockinfo->addr.sin_family=AF_INET; + memcpy((char *)&(udp_sockinfo->addr.sin_addr), &haddr, sizeof(haddr)); + udp_sockinfo->addr.sin_port = htons(port); + + log_msg(LOG_DEBUG, "Socket created"); + return 0; +} + +FILE *create_tcp_connection(char *hostname, int port){ + int sock; + struct sockaddr_in addr; + struct in_addr haddr; + FILE *f; + + log_msg(LOG_DEBUG, "Creating tcp socket"); + if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0){ + log_msg(LOG_CRIT, "Failed to make TCP Socket"); + return NULL; } - reply=sock_comm(fm_fd_r, fm_fd_w, "LASTMODIFIED"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0)){ - errf("Server error (%m)"); - return -1; + if((get_host_addr(hostname, &haddr))!=0){ + log_msg(LOG_CRIT, "Failed to lookup name for %s", hostname); + return NULL; } - if((ihost_state->last_modified=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); - return -1; - } - - reply=sock_comm(fm_fd_r, fm_fd_w, "FILELIST"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0)){ - errf("Server error (%m)"); - return -1; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + memcpy(&addr.sin_addr, &haddr, sizeof(haddr)); + addr.sin_port = htons(port); + + log_msg(LOG_DEBUG, "Creating a tcp connection"); + if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) !=0){ + log_msg(LOG_CRIT, "Failed to connect to hostname %s on port %d", hostname, port); + return NULL; } - if((ihost_state->files_list=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); - return -1; - } - reply=sock_comm(fm_fd_r, fm_fd_w, "FQDN"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5)==0)){ - errf("Server error (%m)"); - return -1; + if((f=fdopen(sock, "r+"))==NULL){ + log_msg(LOG_CRIT, "Failed to connect to open filedescriptor on tcp connection"); + close(sock); + return NULL; } - if((ihost_state->my_fqdn=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); + + return f; +} + +int tcp_comm(FILE *f, char *send, char **response, char *expected){ + + log_msg(LOG_DEBUG, "Sending %s", send); + fprintf(f, "%s\n", send); + fflush(f); + *response=fpgetline(f); + fseek(f, 0, SEEK_CUR); + + if(*response!=NULL) log_msg(LOG_DEBUG, "Recieved %s", *response); + + if( (*response==NULL) || (strcmp(*response, "ERROR")==0) ) return -1; + + if(expected==NULL) return 0; + + if((strcmp(expected, *response))==0) return 0; + + log_msg(LOG_DEBUG, "Did not get expected response"); + return -1; +} + +int tcp_comm_strdup(FILE *f, char *send, char **response, char *expected){ + if((tcp_comm(f, send, response, expected))!=0){ return -1; } - reply=sock_comm(fm_fd_r, fm_fd_w, "UDPUpdateTime"); - if(reply== NULL){ - errf("Server error (%m)"); - return -1; + *response=strdup(*response); + if (response==NULL) return -1; + + return 0; +} + +int ihost_getconfig(ihost_state_t *ihost_state){ + + FILE *tcp_con; + char *response; + char *response_ptr; + + /* Keep these in case of a failure and so it can keep running on the old config */ + char *file_list=NULL; + char *last_modified=NULL; + char *host_fqdn=NULL; + char *host_ip=NULL; + int udp_update_time=0; + char *server_fqdn=NULL; + int server_udp_port=0; + time_t config_ttl=0; + + if((tcp_con=create_tcp_connection(ihost_state->filtermanager_host, ihost_state->filtermanager_port))==NULL){ + goto error; } - if (strncasecmp(reply, "ERROR", 5) != 0){ - ihost_state->udp_update_time=atoi(reply); - } - reply=sock_comm(fm_fd_r, fm_fd_w, "TCPUpdateTime"); - if(reply== NULL){ - errf("Server error (%m)"); - return -1; + if(ihost_state->file_list!=NULL || ihost_state->last_modified!=NULL){ + if(tcp_con==NULL){ + goto error; + } + + if((tcp_comm(tcp_con, "CHECKCONFIG", &response, "OK"))!=0){ + goto error; + } + + if((tcp_comm(tcp_con, ihost_state->file_list, &response, "OK"))!=0){ + goto error; + } + + if((tcp_comm(tcp_con, ihost_state->last_modified, &response, "OK"))==0){ + if((tcp_comm(tcp_con, "END", &response, "OK"))==0){ + goto error; + } + fclose(tcp_con); + return 0; + }else{ + if((strcmp(response, "EXPIRED"))!=0){ + goto error; + } + } } - if (strncasecmp(reply, "ERROR", 5) != 0){ - ihost_state->tcp_update_time=atoi(reply); - } - reply=sock_comm(fm_fd_r, fm_fd_w, "ENDCONFIG"); - if(reply== NULL){ - errf("Server error (%m)"); - return -1; + /* If we got to here, the config must of expired */ + + if((tcp_comm(tcp_con, "STARTCONFIG", &response, "OK"))!=0){ + goto error; } - reply=sock_comm(fm_fd_r, fm_fd_w, "FILTER"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5)==0)){ - errf("Server error FILTER failed (%m)"); - return -1; + if((tcp_comm_strdup(tcp_con, "LASTMODIFIED", &response, NULL))!=0){ + goto error; } - reply_ptr=strchr(reply,';'); - if (reply_ptr==NULL){ - errf("Incorrect data returned"); - return -1; + last_modified=response; + + if((tcp_comm_strdup(tcp_con, "FILELIST", &response, NULL))!=0){ + goto error; } - *reply_ptr='\0'; - if((ihost_state->server_fqdn=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); - return -1; + file_list=response; + + if((tcp_comm_strdup(tcp_con, "FQDN", &response, NULL))!=0){ + goto error; } - reply=reply_ptr + 1; - reply_ptr=strchr(reply,';'); - if (reply_ptr==NULL){ - errf("Incorrect data returned 2"); - return -1; + host_fqdn=response; + + if((tcp_comm_strdup(tcp_con, "IP", &response, NULL))!=0){ + goto error; } - *reply_ptr='\0'; - ihost_state->server_udp_port=atoi(reply); - reply=reply_ptr+1; - ihost_state->server_tcp_port=atoi(reply); - if ((ihost_state->server_tcp_port==0) || (ihost_state->server_udp_port==0)){ - errf("Incorrect data returned 3 "); - return -1; + host_ip=response; + + if((tcp_comm(tcp_con, "UDPUpdateTime", &response, NULL))!=0){ + goto error; } + udp_update_time=atoi(response); - reply=sock_comm(fm_fd_r, fm_fd_w, "END"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0 )){ - errf("Server error (%m)"); - return -1; + if((tcp_comm(tcp_con, "ConfigTTL", &response, NULL))!=0){ + goto error; } + config_ttl=atoi(response); - if(fclose(fm_fd_r) !=0){ - errf("Failed to close read FD (%m)"); - return -1; + if((tcp_comm(tcp_con, "ENDCONFIG", &response, NULL))!=0){ + goto error; } - if(fclose(fm_fd_w) !=0){ - errf("Failed to close write FD (%m)"); - return -1; + + if((tcp_comm(tcp_con, "FILTER", &response, NULL))!=0){ + goto error; + }else{ + response_ptr=strchr(response,';'); + if(response_ptr==NULL){ + log_msg(LOG_ERR, "Incorrect data sent by server"); + goto error; + } + *response_ptr='\0'; + server_fqdn=strdup(response); + if(server_fqdn==NULL){ + goto error; + } + response_ptr++; + if(response_ptr==NULL){ + log_msg(LOG_ERR, "Incorrect data sent by server"); + goto error; + } + + printf("string : %s\n", response_ptr); + server_udp_port=atoi(response_ptr); + + if (server_udp_port==0){ + log_msg(LOG_ERR, "Incorrect data sent by server"); + goto error; + } } + + if((tcp_comm(tcp_con, "END", &response, "OK"))!=0){ + goto error; + } + fclose(tcp_con); + + /* We have the data we need, and its all been read correctly */ + + /* Free the old data before pointing them to the new data. m_free copes should + * this already be NULL */ + if(ihost_state->file_list!=NULL) free(ihost_state->file_list); + if(ihost_state->last_modified!=NULL) free(ihost_state->last_modified); + if(ihost_state->host_fqdn!=NULL) free(ihost_state->host_fqdn); + if(ihost_state->server_fqdn!=NULL) free(ihost_state->server_fqdn); + if(ihost_state->host_ip!=NULL) free(ihost_state->host_ip); + + ihost_state->file_list=file_list; + ihost_state->last_modified=last_modified; + ihost_state->host_fqdn=host_fqdn; + ihost_state->host_ip=host_ip; + ihost_state->server_fqdn=server_fqdn; + ihost_state->server_udp_port=server_udp_port; + ihost_state->udp_update_time=udp_update_time; + ihost_state->config_ttl=config_ttl; + + log_msg(LOG_DEBUG, "UDP Update time %d", udp_update_time); + log_msg(LOG_DEBUG, "Configure ttl %d", config_ttl); + return 0; + +error: + + if(file_list!=NULL) free(file_list); + if(last_modified!=NULL) free(last_modified); + if(host_fqdn!=NULL) free(host_fqdn); + if(server_fqdn!=NULL) free(server_fqdn); + if(host_ip!=NULL) free(host_ip); + fclose(tcp_con); + + return -1; } -int heartbeat(ihost_state_t *ihost_state){ - struct sockaddr_in addr; - struct in_addr haddr; - int sd; - FILE *fm_fd_r, *fm_fd_w; - char *reply; - int exitcode=0; +int get_system_stats(int seq_no, ihost_state_t *ihost_state, char *xml, int size){ + char tmp[size]; + cpu_percent_t *cpu_percent; + mem_stat_t *mem_stats; + load_stat_t *load_stats; + user_stat_t *user_stats; + swap_stat_t *swap_stats; + general_stat_t *general_stats; + disk_stat_t *disk_stats; + diskio_stat_t *diskio_stats; + process_stat_t *process_stats; + network_stat_t *network_stats; + page_stat_t *page_stats; + int disk_entries=0; + int diskio_entries=0; + int network_entries=0; - if ((sd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { - errf("Can't create AF_INET socket (%m)"); - return -1; - } + int counter; + long long x; + long long y; - if (get_host_addr(ihost_state->server_fqdn, &haddr) != 0){ - errf("Failed to resolve address %s (%m)", ihost_state->fm_host); - return -1; - } + /* Print start of the packet we want */ + snprintf(xml, size, "", \ + seq_no, ihost_state->host_fqdn, time(NULL), ihost_state->host_ip); - memset(&addr, 0, sizeof addr); - addr.sin_family = AF_INET; - memcpy(&addr.sin_addr, &haddr, sizeof haddr); - addr.sin_port = htons(ihost_state->server_tcp_port); + /* Get cpu stats, check it is correct, then fill in its entry for the xml */ + if((cpu_percent=cpu_percent_usage())==NULL){ + log_msg(LOG_CRIT, "Failed to get cpu statistics"); + }else{ + snprintf(tmp, size, \ + "%3.2f%3.2f%3.2f%3.2f%3.2f", \ + cpu_percent->user, \ + cpu_percent->kernel, \ + cpu_percent->idle, \ + cpu_percent->iowait, \ + cpu_percent->swap); - if (connect(sd, (struct sockaddr *)&addr, sizeof addr) != 0) { - errf("Failed to connect to %s on port %d (%m)", ihost_state->fm_host, ihost_state->fm_port); - return -1; - } + if(strlcat(xml, tmp, size) >= size) goto too_big_error; + } - /* Need to open 2 files, one for reading one for writing, as it gets confused if we only use 1 :) */ - if ((fm_fd_r=fdopen(sd,"r")) == NULL){ - errf("Failed to open stream (%m)"); - return -1; - } + + /*Get mem stats, and fill in xml */ + if((mem_stats=get_memory_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get memory statistics"); + }else{ + snprintf(tmp, size, \ + "%lld%lld%lld%lld", \ + mem_stats->total, \ + mem_stats->free, \ + mem_stats->used, \ + mem_stats->cache); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; + } - if ((fm_fd_w=fdopen(dup(sd),"w")) == NULL){ - errf("Failed to open stream (%m)"); - return -1; - } - reply=sock_comm(fm_fd_r, fm_fd_w, "HEARTBEAT"); - if ((reply==NULL) || (strncasecmp(reply, "ERROR", 5) == 0) ) { - errf("Server error"); - return -1; - } + /* Get load stats */ + if((load_stats=get_load_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get load statistics"); + }else{ + snprintf(tmp, size, \ + "%.2lf%.2lf%.2lf", \ + load_stats->min1, \ + load_stats->min5, \ + load_stats->min15); + if(strlcat(xml, tmp, size) >= size) goto too_big_error; + } - reply=sock_comm(fm_fd_r, fm_fd_w, "CONFIG"); - if ((reply==NULL) || (strncasecmp(reply, "ERROR", 5) == 0) ) { - errf("Server error"); - return -1; - } - reply=sock_comm(fm_fd_r, fm_fd_w, ihost_state->files_list); - if ((reply==NULL) || (strncasecmp(reply, "OK", 2) != 0) ) { - errf("Server error"); - return -1; - } + /* get user stats */ + + if((user_stats=get_user_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get user statistics"); + }else{ - reply=sock_comm(fm_fd_r, fm_fd_w, ihost_state->last_modified); - if (reply==NULL) { - errf("Server error"); - return -1; - } - if (strncasecmp(reply, "ERROR", 5) == 0){ - /* Means the config has changed */ - exitcode=RECONFIGURE_RETURN_CODE; + snprintf(tmp, size, \ + "%s%d", \ + user_stats->name_list, \ + user_stats->num_entries); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; } - reply=sock_comm(fm_fd_r, fm_fd_w, "KEY"); - if ((reply==NULL) || (strncasecmp(reply, "ERROR", 5) == 0) ) { - errf("Server error"); - return -1; - } - if (ihost_state->key!=NULL) free(ihost_state->key); - - if((ihost_state->key=strdup(reply)) == NULL){ - errf("strdup failed (%m)"); - return -1; - } - reply=sock_comm(fm_fd_r, fm_fd_w, "ENDHEARTBEAT"); - if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0 )){ - errf("Server error (%m)"); - return -1; - } - fflush(fm_fd_r); - fflush(fm_fd_w); + /* swap stats */ + if((swap_stats=get_swap_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get swap statistics"); + }else{ + snprintf(tmp, size, \ + "%lld%lld%lld",\ + swap_stats->total, \ + swap_stats->used, \ + swap_stats->free); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; + } - if(fclose(fm_fd_r) !=0){ - errf("Failed to close read FD (%m)"); - return -1; - } - if(fclose(fm_fd_w) !=0){ - errf("Failed to close write FD (%m)"); - return -1; - } - return exitcode; -} + /* general stats */ + + if((general_stats=get_general_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get general statistics"); + }else{ + snprintf(tmp, size, \ + "%s%s%s%s%s%ld", \ + general_stats->os_name, \ + general_stats->os_release, \ + general_stats->os_version, \ + general_stats->hostname, \ + general_stats->platform, \ + (long)general_stats->uptime); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; + + } -char *stat_grab(ihost_state_t *ihost_state, int counter){ -#define NUM_STATS 9 - char *stats[NUM_STATS]; - char *xml_data=NULL; - char *xml_data_p; - int x=0; - stats[0]=get_cpu_stats(); - stats[1]=get_disk_stats(); - stats[2]=get_load_stats(); - stats[3]=get_memory_stats(); - stats[4]=get_os_info(); - stats[5]=get_page_stats(); - stats[6]=get_process_stats(); - stats[7]=get_swap_stats(); - stats[8]=get_user_stats(); + /* process stats */ + if((process_stats=get_process_stats())==NULL){ + log_msg(LOG_CRIT, "Failed to get general statistics"); + }else{ + snprintf(tmp, size, \ + "%d%d%d%d%d",\ + process_stats->sleeping, \ + process_stats->running, \ + process_stats->zombie, \ + process_stats->stopped, \ + process_stats->total); - for(;x= size) goto too_big_error; + + } + + + /* Get paging stats */ + if((page_stats=get_page_stats_diff())==NULL){ + log_msg(LOG_CRIT, "Failed to get paging statistics"); + }else{ + if(page_stats->systime!=0){ + x=page_stats->pages_pagein / page_stats->systime; + y=page_stats->pages_pageout / page_stats->systime; }else{ - xml_data_p=xml_data; - if((xml_data=strf("%s%s", xml_data, stats[x])) == NULL){ - errf("str failed (%m)"); - return NULL; - } - free(xml_data_p); + x=page_stats->pages_pagein; + y=page_stats->pages_pageout; } - free(stats[x]); + snprintf(tmp, size, \ + "%lld%lld", \ + x, \ + y); + + if(strlcat(xml, tmp, size) >= size) goto too_big_error; } - xml_data_p=xml_data; - xml_data=strf("%s", counter, ihost_state->my_fqdn, time(NULL), "127.0.0.1", ihost_state->key, xml_data); - free(xml_data_p); + + + /* get diskio stats */ - return xml_data; -} + if((diskio_stats=get_diskio_stats_diff(&diskio_entries))==NULL){ + log_msg(LOG_CRIT, "Failed to get diskio statistics"); + }else{ + strlcat(xml, "", size); + for(counter=0;countersystime!=0){ + x=diskio_stats->read_bytes / diskio_stats->systime; + y=diskio_stats->write_bytes / diskio_stats->systime; + }else{ + x=diskio_stats->read_bytes; + y=diskio_stats->write_bytes; + } + + snprintf(tmp, size, \ + "", \ + counter, \ + diskio_stats->disk_name, \ + x, \ + y, \ + counter); - int sd; - size_t len; + strlcat(xml, tmp, size); + diskio_stats++; + } - len=strlen(data_stream); - if(len>UDP_MAX_PACKET_SIZE){ - errf("Too big to send to server. Please reconfigure client and server and recompile"); - exit(1); + if(strlcat(xml, "", size) >= size) goto too_big_error; + } + - if (get_host_addr(ihost_state->server_fqdn, &haddr) != 0){ - errf("Failed to resolve address %s (%m)", ihost_state->fm_host); - return -1; - } + /* get networks stats */ + + if((network_stats=get_network_stats_diff(&network_entries))==NULL){ + log_msg(LOG_CRIT, "Failed to get network statistics"); + }else{ + strlcat(xml, "", size); + for(counter=0;countersystime!=0){ + x=network_stats->rx / network_stats->systime; + y=network_stats->tx / network_stats->systime; + }else{ + x=network_stats->rx; + y=network_stats->tx; + } - if((sd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){ - errf("failed to create UDP socket (%m)"); - return -1; + snprintf(tmp, size, \ + "", \ + counter, \ + network_stats->interface_name, \ + x, \ + y, \ + counter); + + strlcat(xml, tmp, size); + network_stats++; + } + + if(strlcat(xml, "", size) >= size) goto too_big_error; + } - memset(&addr, 0, sizeof(addr)); - addr.sin_family=AF_INET; - memcpy((char *)&addr.sin_addr, &haddr, sizeof haddr); - addr.sin_port = htons(ihost_state->server_udp_port); - if((sendto(sd, data_stream, len, 0, (struct sockaddr *) &addr, sizeof(addr))) != len){ - errf("Send the wrong number of bytes (%m)"); - return -1; + /* get disk stats */ + + if((disk_stats=get_disk_stats(&disk_entries))==NULL){ + log_msg(LOG_CRIT, "Failed to get disk statistics"); + }else{ + strlcat(xml, "", size); + for(counter=0;counter", \ + counter, \ + disk_stats->device_name, \ + disk_stats->mnt_point, \ + disk_stats->fs_type, \ + disk_stats->size, \ + disk_stats->used, \ + disk_stats->avail, \ + disk_stats->total_inodes, \ + disk_stats->used_inodes, \ + disk_stats->free_inodes, \ + counter); + + strlcat(xml, tmp, size); + + disk_stats++; + } + + if(strlcat(xml, "", size) >= size) goto too_big_error; + } + - close(sd); + if(strlcat(xml, "", size) >= size) goto too_big_error; - return 0; + /*If we got to here, it should of all been filled in nicely now */ + return 0; + +too_big_error: + log_msg(LOG_ERR, "UDP Packet is too large. Throwing away the packet"); + return -1; } + + +void usage(char *progname){ + fprintf(stderr, "Usage %s [options] server port\n", progname); + fprintf(stderr, "Options\n"); + fprintf(stderr, " -v Verbose mode,-vv would make even more verbose\n"); + fprintf(stderr, " -f Foreground mode, print errors to stderr\n"); + fprintf(stderr, " -V Print version number\n"); + fprintf(stderr, " -h Prints this help page\n"); + exit(1); +} + int main(int argc, char **argv){ + ihost_state_t ihost_state; - int heartbeat_exit; - int counter=0; - long udp_time=0, tcp_time=0, stat_grab_time=0, cur_time=0; - int sleep_delay=0; - char *xml_stats; + udp_sockinfo_t udp_sockinfo; + + int cmdopt; + extern int optind; + pid_t pid; + FILE *f; + int packet_num=0; + int len; - /* NULL'ify so i can tell if i need to free it or not */ - ihost_state.fm_host=NULL; - ihost_state.my_fqdn=NULL; - ihost_state.server_fqdn=NULL; - ihost_state.last_modified=NULL; - ihost_state.files_list=NULL; - ihost_state.key=NULL; + char packet[MAX_UDP_PACKET_SIZE]; - errf_set_progname(argv[0]); - if(argc!=3){ - errf_usage(" "); + time_t cur_time, sleep_delay, udp_time=0, config_time=0; + + /* Set default settings */ + ihost_config.verbose=1; + ihost_config.daemon=1; + /* Set all errors to go down stderr until told otherwise */ + ihost_config.log=stderr; + + /* Blank ihost_state to default settings */ + ihost_state.filtermanager_host=NULL; + ihost_state.host_fqdn=NULL; + ihost_state.host_ip=NULL; + ihost_state.server_fqdn=NULL; + ihost_state.file_list=NULL; + ihost_state.last_modified=NULL; + + while((cmdopt=getopt(argc, argv, "vfhV")) != -1){ + switch(cmdopt){ + case 'v': + ihost_config.verbose++; + break; + + case 'f': + /* Force syslog logging since stderr will be closed in this case */ + ihost_config.daemon=0; + break; + + case 'h': + usage(argv[0]); + break; + + case 'V': + fprintf(stderr, "%s version %s\n", argv[0], VERSION); + break; + + default: + usage(argv[0]); + exit(1); + } + } + + if(argc!=optind+2){ + usage(argv[0]); + exit(1); + } + + ihost_state.filtermanager_host=strdup(argv[optind]); + ihost_state.filtermanager_port=atoi(argv[optind+1]); + + if(gethostbyname(ihost_state.filtermanager_host)==NULL){ + log_msg(LOG_CRIT, "Failed to lookup hostname. Please check settings"); exit(1); } + if(ihost_state.filtermanager_port==0){ + log_msg(LOG_ERR, "Invalid port number"); + exit(1); + } - ihost_state.fm_host=argv[1]; - ihost_state.fm_port=atoi(argv[2]); + if(ihost_config.daemon){ + pid=fork(); + if(pid==-1){ + log_msg(LOG_CRIT, "Failed to background exiting"); + exit(1); + }else if(pid!=0){ + /* Parent process */ + return 0; + } + /* We should now be in the background*/ + if(setsid()==-1){ + log_msg(LOG_CRIT, "setsid failed"); + exit(1); + } + + if((ihost_config.log=fopen(LOG_FILE, "a"))==NULL){ + ihost_config.log=stderr; + log_msg(LOG_CRIT, "Failed to open Logfiles %s for writing", LOG_FILE); + exit(1); + } - if(ihost_configure(&ihost_state)!=0){ - errf("configure failed"); - /* Ok, ideally we prob should have 2 copies of the structure and carry on if this - happens.. But we dont :) (at the moment) */ - exit(1); + fclose(stdin); + fclose(stdout); + fclose(stderr); + + } + + log_msg(LOG_INFO, "Starting ihost"); + + log_msg(LOG_DEBUG,"Writing PID FILE"); + + pid=getpid(); + + if((f=fopen(PID_FILE,"w")) == NULL){ + log_msg(LOG_CRIT, "Failed to write PID file"); + }else{ + if((fprintf(f,"%d",(int)pid)) <= 0 ){ + log_msg(LOG_CRIT, "Failed to write PID file"); + } + if((fclose(f))!=0){ + log_msg(LOG_CRIT, "failed to close PID file"); + } + } + + /* Get the initial config from the filter manager. Should this fail, + * wait, and then try again. */ + + get_diskio_stats_diff(&packet_num); + packet_num=0; + + while(ihost_getconfig(&ihost_state)!=0){ + log_msg(LOG_ERR, "Failed to get ihost config"); + sleep(10); } + printf("%s\n%d\n", ihost_state.server_fqdn, ihost_state.server_udp_port); + while((create_udp_sockinfo(&udp_sockinfo, ihost_state.server_fqdn, ihost_state.server_udp_port))!=0){ + log_msg(LOG_ERR, "Failed to create udp socket"); + sleep(10); + } + + config_time=time(NULL)+ihost_state.config_ttl; + + /* Now have config.. collect data and send as often as required */ for(;;){ cur_time=time(NULL); - if(cur_time>=tcp_time){ - /*printf("sending TCP\n");*/ - heartbeat_exit=heartbeat(&ihost_state); - if(heartbeat_exit==RECONFIGURE_RETURN_CODE){ - /*errf("heartbeat needs to be reconfigured");*/ - ihost_configure(&ihost_state); - /* So udp doesn't wait til next sending before updating */ - udp_time=0; - } - if(heartbeat_exit==-1){ - errf("ah crap"); - exit(1); - } - tcp_time=time(NULL)+ihost_state.tcp_update_time; - } if(cur_time>=udp_time){ - /*printf("sending UDP\n");*/ - stat_grab_time=time(NULL); - if((xml_stats=stat_grab(&ihost_state, counter)) == NULL){ - errf("Failed to get stats (%m)"); - exit(1); + if((get_system_stats(packet_num++, &ihost_state, packet, MAX_UDP_PACKET_SIZE))!=0){ + log_msg(LOG_ERR, "Failed to get system stats"); } - stat_grab_time=time(NULL)-stat_grab_time; - send_stats(&ihost_state, xml_stats); - free(xml_stats); - udp_time=time(NULL)+ihost_state.udp_update_time-stat_grab_time; + + len=strlen(packet); + log_msg(LOG_DEBUG, "Packet size: %d\nPacket: %s\n", len, packet); + + if((sendto(udp_sockinfo.sock, packet, len, 0, (struct sockaddr *) &udp_sockinfo.addr, sizeof(udp_sockinfo.addr)))!=len){ + log_msg(LOG_CRIT, "Failed to send packet"); + } + udp_time=cur_time+ihost_state.udp_update_time; + log_msg(LOG_DEBUG, "Next packet should be sent on %d", udp_time); } + + if(cur_time>=config_time){ + if(ihost_getconfig(&ihost_state)!=0){ + /* If we can't get the config, try again 5 minutes time */ + log_msg(LOG_ERR, "Failed to get config, try again 5 minutes time"); + config_time=time(NULL)+300; + }else{ + close(udp_sockinfo.sock); - if(tcp_time0) sleep(sleep_delay); - } - return 0; + } + + return(0); } -