From f09be2ba1252128847006f647c3da620bf280a1d Mon Sep 17 00:00:00 2001 From: Maxime Menault Date: Mon, 16 Sep 2024 20:38:18 +0200 Subject: [PATCH] First commit --- Makefile => ping-report/Makefile | 0 README.md => ping-report/README.md | 0 ping-report/include/daemon.h | 7 + ping-report/include/db-sqlite.h | 8 + ping-report/include/ping-report.h | 4 + ping-report/include/stats.h | 8 + ping-report/include/utils.h | 9 + .../install-ping-report.sh | 0 ping-report/res/ping-report-db.sql | 58 ++++ ping-report/res/ping-report.sh | 34 +++ ping-report/src/daemon.c | 218 +++++++++++++++ ping-report/src/db-sqlite.c | 66 +++++ ping-report/src/ping-report.c | 38 +++ ping-report/src/stats.c | 249 ++++++++++++++++++ ping-report/src/utils.c | 60 +++++ 15 files changed, 759 insertions(+) rename Makefile => ping-report/Makefile (100%) rename README.md => ping-report/README.md (100%) create mode 100644 ping-report/include/daemon.h create mode 100644 ping-report/include/db-sqlite.h create mode 100644 ping-report/include/ping-report.h create mode 100644 ping-report/include/stats.h create mode 100644 ping-report/include/utils.h rename install-ping-report.sh => ping-report/install-ping-report.sh (100%) mode change 100644 => 100755 create mode 100644 ping-report/res/ping-report-db.sql create mode 100755 ping-report/res/ping-report.sh create mode 100644 ping-report/src/daemon.c create mode 100644 ping-report/src/db-sqlite.c create mode 100644 ping-report/src/ping-report.c create mode 100644 ping-report/src/stats.c create mode 100644 ping-report/src/utils.c diff --git a/Makefile b/ping-report/Makefile similarity index 100% rename from Makefile rename to ping-report/Makefile diff --git a/README.md b/ping-report/README.md similarity index 100% rename from README.md rename to ping-report/README.md diff --git a/ping-report/include/daemon.h b/ping-report/include/daemon.h new file mode 100644 index 0000000..68352a5 --- /dev/null +++ b/ping-report/include/daemon.h @@ -0,0 +1,7 @@ +#ifndef DAEMON_H +#define DAEMON_H + +int create_daemon(); +void daemon_work(); + +#endif diff --git a/ping-report/include/db-sqlite.h b/ping-report/include/db-sqlite.h new file mode 100644 index 0000000..fdbb130 --- /dev/null +++ b/ping-report/include/db-sqlite.h @@ -0,0 +1,8 @@ +#ifndef DB_SQLITE_H +#define DB_SQLITE_H + +int db_connect(); +int db_disconnect(); +int insert_hourly_report(double mean,double max,double min,int high,int loss,int reached); + +#endif diff --git a/ping-report/include/ping-report.h b/ping-report/include/ping-report.h new file mode 100644 index 0000000..0bacfd7 --- /dev/null +++ b/ping-report/include/ping-report.h @@ -0,0 +1,4 @@ +#ifndef PING_REPORT_H +#define PING_REPORT_H + +#endif diff --git a/ping-report/include/stats.h b/ping-report/include/stats.h new file mode 100644 index 0000000..931e6b2 --- /dev/null +++ b/ping-report/include/stats.h @@ -0,0 +1,8 @@ +#ifndef STATS_H +#define STATS_H + +/*@null@*/char* get_ping_from_temp_log(); +void write_ping_log(char* new_ping); +void set_stats_ping(); + +#endif diff --git a/ping-report/include/utils.h b/ping-report/include/utils.h new file mode 100644 index 0000000..eb215cb --- /dev/null +++ b/ping-report/include/utils.h @@ -0,0 +1,9 @@ +#ifndef UTILS_H +#define UTILS_H + +#define STATUS_LOG "/var/log/ping-report/status.log" + +void write_pid_file(); +void remove_file(char* filename); + +#endif diff --git a/install-ping-report.sh b/ping-report/install-ping-report.sh old mode 100644 new mode 100755 similarity index 100% rename from install-ping-report.sh rename to ping-report/install-ping-report.sh diff --git a/ping-report/res/ping-report-db.sql b/ping-report/res/ping-report-db.sql new file mode 100644 index 0000000..8a8e414 --- /dev/null +++ b/ping-report/res/ping-report-db.sql @@ -0,0 +1,58 @@ +CREATE TABLE HourlyReport( + ping_max FLOAT NOT NULL, + ping_min FLOAT NOT NULL, + ping_mean FLOAT NOT NULL, + nb_ping_high INT NOT NULL, + nb_ping_loss INT NOT NULL, + nb_ping_reached INT NOT NULL, + report_day DATE NOT NULL, + report_hour INT NOT NULL +); + +CREATE VIEW DailyReport AS +SELECT + H.report_day, + MAX(H.ping_max) AS daily_worst_ping, + MIN(H.ping_min) AS daily_best_ping, + AVG(H.ping_mean) AS daily_mean_ping, + SUM(H.nb_ping_high) AS daily_high_ping, + SUM(H.nb_ping_loss) AS daily_loss_ping, + SUM(H.nb_ping_reached) AS daily_reached_ping, + ( + SELECT + SH.report_hour + FROM + HourlyReport SH + WHERE + SH.ping_mean = ( + SELECT + MIN(SSH.ping_mean) + FROM + HourlyReport SSH + WHERE + SSH.report_day = sh.report_day + ) + AND + SH.report_day = H.report_day + ) daily_best_hour, + ( + SELECT + SH.report_hour + FROM + HourlyReport SH + WHERE + SH.ping_mean = ( + SELECT + MAX(SSH.ping_mean) + FROM + HourlyReport SSH + WHERE + SSH.report_day = sh.report_day + ) + AND + SH.report_day = H.report_day + ) daily_worst_hour +FROM + HourlyReport H +GROUP BY + report_day diff --git a/ping-report/res/ping-report.sh b/ping-report/res/ping-report.sh new file mode 100755 index 0000000..3d48d57 --- /dev/null +++ b/ping-report/res/ping-report.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +BIN=/opt/ping-report/bin/ping-report +PID=/var/log/ping-report/pid.log +STATUS=/var/log/ping-report/status.log + +case $1 in +start) sudo echo "STARTED" > $STATUS; + sudo $BIN; + echo "ping-report started";; +end) sudo echo "STOP" > $STATUS; + sudo rm $PID; + sleep 2; + sudo echo "ENDED" > $STATUS; + echo "ping-report ended";; +kill) sudo kill `cat $PID`; + sudo rm $PID; + sudo echo "ENDED" > $STATUS; + echo "ping-report killed";; +restart) sudo echo "STOP" > $STATUS; + sleep 2; + sudo rm $PID; + sudo echo "STARTED" > $STATUS; + sudo $BIN; + echo "ping-report restarted";; +status) if test -f "$PID"; then + echo "ping-report is alive"; + else + echo "ping-report is not started"; + fi;; +*) echo "Usage : ping-report [start | end | kill | restart]"; + exit 1;; +esac + diff --git a/ping-report/src/daemon.c b/ping-report/src/daemon.c new file mode 100644 index 0000000..7cbbc51 --- /dev/null +++ b/ping-report/src/daemon.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/daemon.h" +#include "../include/utils.h" +#include "../include/stats.h" +#include "../include/db-sqlite.h" + +/* + -- create_daemon -- + Desc : + Function which create a daemon + In-param : + None + Out-param : + None + Return value : + -1 : Error fork + 0 : Daemon branch + 1 : Parent process branch + +*/ +int create_daemon(){ + + /* Variables */ + pid_t pid; + int fd; + + /* Fork a new process */ + pid = (pid_t) fork(); + + if(pid < 0){ + /* Error while forking */ + /* todo : add log */ + return -1; + } + if(pid > 0){ + /* Parent process branch : quit function */ + return 1; + } + + /* Son process branch */ + + /* Set file permissions */ + (void) umask(0); + + /* Change working directory to root directory */ + (void) chdir("/"); + + /* Close all open file descriptors */ + for(fd = (int) sysconf(_SC_OPEN_MAX); fd >= 0; fd--){ + (void) close(fd); + } + + return 0; +} + +/* + -- ping_request -- + Desc : + Ping the DNS (1.1.1.1) then write the ping in log file + In-param : + None + Out-param : + None + Return value : + None +*/ +static void ping_request(){ + + /* Variables */ + char* ping; + static char command[128] = "ping -c 1 1.1.1.1 > /var/log/ping-report/last-ping.log"; + + /* ping command */ + (void) system(command); + /* Get ping value as a string */ + ping = get_ping_from_temp_log(); + if(ping != NULL) { + /* Write ping in all-ping.log */ + write_ping_log(ping); + } + +} + +/* + -- send_check -- + Desc : + Send if send_stats_ping is needed and if so, do it + In-param : + None + Out-param : + None + Return value : + None +*/ +static void send_check(){ + + /* Variables */ + time_t t; + struct tm* utc_time; + static int flag = 1; + + /* Get time */ + t = time(NULL); + utc_time = localtime(&t); + + /* Set flag to avoid sending multiple time the same data at HH:00 */ + if((utc_time->tm_min != 0)&& (flag == 0)){ + flag = 1; + } + + /* if time == HH:00, insert stats in db */ + if((utc_time->tm_min == 0) && (flag != 0)){ + set_stats_ping(); + remove_file("/var/log/ping-report/all-ping.log"); + flag = 0; + } + +} + +/* + -- check_keep_working -- + Desc : + Check if ping-report need to be ended + In-param : + None + Out-param : + None + Return value : + keep_working : 1 continue, 0 end +*/ +static int check_keep_working(){ + + /* Variables */ + FILE* fd; + char read_line[5]; + + fd = fopen(STATUS_LOG,"r"); + + if(fd == NULL){ + // Error occured while reading status log file, stop ping-report + printf("Err\n"); + return 0; + } + + /* Read file */ + if(fread(read_line,sizeof(char),4,fd) != 0){ + + (void) fclose(fd); + read_line[4] = '\0'; + + if(strcmp(read_line,"STOP") == 0){ + // stop ping-report + printf("Stop\n"); + return 0; + }else{ + // continue ping-report + printf("%s : Continue\n",read_line); + return 1; + } + }else{ + // Error occured while reading status log file, stop ping-report + printf("Nothing to read\n"); + (void) fclose(fd); + return 1; + } +} + +/* + -- daemon_work -- + Desc : + Function which contain main loop of the daemon + In-param : + None + Out-param : + None + Return value : + None +*/ +void daemon_work(){ + + /* Variables */ + int keep_working = 1; + + /* Write daemon pid in log file */ + write_pid_file(); + + /* Connect db sqlite */ + if(db_connect()){ + return; + } + /* Main loop */ + while(keep_working != 0){ + + /* Launch ping command */ + ping_request(); + + /* Send stats if time is correct */ + send_check(); + + /* Check end ping-report */ + keep_working = check_keep_working(); + + /* ping_interval 100 ms */ + usleep(100*1000); + + } + + /* Disconnect sqlite db */ + db_disconnect(); +} diff --git a/ping-report/src/db-sqlite.c b/ping-report/src/db-sqlite.c new file mode 100644 index 0000000..914f89a --- /dev/null +++ b/ping-report/src/db-sqlite.c @@ -0,0 +1,66 @@ +#include +#include +#include + +#include "../include/stats.h" +#include "../include/db-sqlite.h" + +/* Globals for this file */ +static sqlite3 *db = NULL; +static char db_filename[] = "/srv/ping-report/ping-report.db"; + +/* + -- db_connect -- + Desc : + Connect the sqlite db + In-param : + None + Out-param : + None + Return value : + sqlite3_open rc +*/ +int db_connect(){ + return sqlite3_open(db_filename,&db); +} + +/* + -- db_disconnect -- + Desc : + Disconnect the sqlite db + In-param : + None + Out-param : + None + Return value : + sqlite3_close rc +*/ +int db_disconnect(){ + return sqlite3_close(db); +} + +/* + -- insert_hourly_report -- + Desc : + Insert ping hourly stats + In-param : + ping value + Out-param : + None + Return value : + sqlite3_exec rc +*/ +int insert_hourly_report(double mean, double max, double min, int high, int loss, int reached){ + + int rc = 0; + char statement[128]; + time_t t = time(NULL); + struct tm* tm = localtime(&t); + + (void) snprintf(statement,128,"INSERT INTO HourlyReport VALUES (%lf,%lf,%lf,%d,%d,%d,'%d-%d-%d',%d)", + max,min,mean,high,loss,reached,tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour); + + rc = sqlite3_exec(db,statement,NULL,NULL,NULL); + + return rc; +} diff --git a/ping-report/src/ping-report.c b/ping-report/src/ping-report.c new file mode 100644 index 0000000..caf6b6d --- /dev/null +++ b/ping-report/src/ping-report.c @@ -0,0 +1,38 @@ +#include "../include/daemon.h" + +/* + -- main -- + Desc : + Main function + In-param : + argc : argument count + argv : argument list + Out-param : + None + Return value : + 0 : Normal end of program + 1 : Error while creating daemon + 2 : Parent process quit + 3 : Unknown error +*/ +int main(/*int argc, char** argv*/){ + + /* Daemon creation */ + switch(create_daemon()){ + case 0: + /* Daemon execution */ + daemon_work(); + break; + case -1: + /* Error : quit program */ + return 1; + case 1: + /* Parent process : quit program */ + return 2; + default: + return 3; + } + + return 0; + +} diff --git a/ping-report/src/stats.c b/ping-report/src/stats.c new file mode 100644 index 0000000..5b343e8 --- /dev/null +++ b/ping-report/src/stats.c @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/utils.h" +#include "../include/stats.h" +#include "../include/db-sqlite.h" + +/* + -- get_ping_from_temp_log -- + Desc : + Function which get the ping from a temp log containing the last ping did by the program + In-param : + None + Out-param : + None + Return value : + Ping value as a string or NULL if an error occured +*/ +/*@null@*/char* get_ping_from_temp_log(){ + + /* Variables */ + FILE* fd = NULL; + char* read_line = NULL; + size_t n = 0; + size_t nmatch = 2; + regex_t *p_reg; + regmatch_t* pmatch; + char* ping = NULL; + int start; + int end; + size_t size_ping; + + /* regex struct memory allocation */ + p_reg = (regex_t *) malloc(sizeof(*p_reg)); + if(p_reg == NULL){ + return ping; /* NULL */ + } + + /* Open ping log file */ + fd = fopen("/var/log/ping-report/last-ping.log","r"); + if(fd == NULL){ + free(p_reg); + return ping; /* NULL */ + } + + /* Construct regex to get ping from log file */ + if(regcomp(p_reg,"time=(.*) ms",REG_EXTENDED) != 0){ + if(p_reg != NULL){ + free(p_reg); + } + (void) fclose(fd); + return ping; /* NULL */ + } + + /* match info memory allocation */ + pmatch = malloc(sizeof(*pmatch) * nmatch); + if(pmatch == NULL){ + (void) fclose(fd); + regfree(p_reg); + free(p_reg); + return ping; /* NULL */ + } + + /* Read file */ + while(getline(&read_line,&n,fd) != -1){ + + if(read_line == NULL){ + break; + } + + /* Exec regex to find ping */ + + if(regexec(p_reg,read_line,nmatch,pmatch,0) == 0){ + + /* Extract ping position from read line */ + start = (int) pmatch[1].rm_so; + end = (int) pmatch[1].rm_eo; + size_ping = (size_t) (end - start); + + /* ping string memory allocation */ + ping = malloc(sizeof(char) * (size_ping+2)); + if(ping == NULL){ + free(read_line); + read_line = NULL; + n = 0; + break; + } + + /* Create ping string */ + (void) strncpy(ping, &read_line[start], size_ping); + ping[size_ping]='\n'; + ping[size_ping+1]='\0'; + + /* Free memory */ + free(read_line); + read_line = NULL; + n = 0; + break; + } + + free(read_line); + read_line = NULL; + n = 0; + } + + /* free allocated memory */ + regfree(p_reg); + free(p_reg); + free(pmatch); + if(read_line != NULL){ + free(read_line); + } + + (void) fclose(fd); + + /* ping may be null, then it must mean that the ping request was lost */ + return ping; +} + +/* + -- write_ping_log -- + Desc : + Function which write a given ping in log file + In-param : + new_ping : string value of a ping + Out-param : + None + Return value : + None +*/ +void write_ping_log(char* new_ping){ + + /* Variables */ + FILE* fd; + + /* Open log file */ + fd = fopen("/var/log/ping-report/all-ping.log","a+"); + + if(fd != NULL){ + if(new_ping == NULL){ + new_ping = (char *) malloc(5*sizeof(char)); + if(new_ping == NULL){ + (void) fclose(fd); + return; + } + (void) snprintf(new_ping,5*sizeof(char),"LOSS"); + } + (void) fwrite(new_ping, sizeof(char), strlen(new_ping), fd); + (void) fclose(fd); + }else{ + perror("write ping : "); + } + + free(new_ping); +} + +/* + -- set_stats_ping -- + Desc : + Function which calculate statistics about ping values, from log file. + In-param : + None + Out-param : + None + Return value : + None +*/ +void set_stats_ping(){ + + /* Variables */ + FILE* fd; + /* Open log file */ + fd = fopen("/var/log/ping-report/all-ping.log","r"); + + if(fd != NULL){ + /* Stats variables */ + double ping = 0.0; + double sum = 0.0; + double max = 0.0; + double min = 100.0; + double mean = 0.0; + int nb_high = 0; + int nb_loss = 0; + int nb_ping = 0; + char* read_line = NULL; + size_t n = 0; + + /* Read file */ + while(getline(&read_line,&n,fd) != -1){ + + /* Check getline error */ + if(read_line == NULL){ + break; + } + + /* Check if the ping is flagged as LOSS */ + if(strcmp(read_line,"LOSS") == 0){ + nb_loss++; + }else{ + /* Evaluate the ping as a double */ + ping = strtod(read_line,NULL); + /* Test null ping */ + if(ping < 0.1){ + /* Ignore null ping */ + }else{ + /* Number of ping readed (for mean calculation) */ + nb_ping++; + /* Max ping */ + if(ping > max){ + max = ping; + } + /* Min ping */ + if(ping < min){ + min = ping; + } + /* Number of ping above 100 ms */ + if(ping > 100.0){ + nb_high++; + } + /* Sum (for mean calculation) */ + sum += ping; + } + } + free(read_line); + n = 0; + } + + /* Mean calculation */ + mean = sum / (double) nb_ping; + (void) fclose(fd); + + insert_hourly_report(mean,max,min,nb_high,nb_loss,nb_ping); + + if(read_line != NULL){ + free(read_line); + } + + }else{ + perror("stats : "); + } +} + + diff --git a/ping-report/src/utils.c b/ping-report/src/utils.c new file mode 100644 index 0000000..5ca4bb5 --- /dev/null +++ b/ping-report/src/utils.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include + +#include "../include/utils.h" + +/* + -- write_pid_file -- + Desc : + write pid in a log file + In-param : + None + Out-param : + None + Return value : + None +*/ +void write_pid_file(){ + + /* Variables */ + FILE* fd; + pid_t pid = (pid_t) getpid(); + char pid_str[16]; + + fd = fopen("/var/log/ping-report/pid.log","w+"); + + if(fd == NULL){ + return; + } + + (void) snprintf(pid_str,16,"%d",(int) pid); + (void) fwrite(pid_str,strlen(pid_str),1,fd); + (void) fclose(fd); + +} + +/* + -- remove_file -- + Desc : + Remove a file from filesystem + In-param : + filename : the name of the file to remove + Out-param : + None + Return value : + None +*/ +void remove_file(char* filename){ + + /* Variable */ + char remove_cmd[128]; + + /* remove file */ + (void) snprintf(remove_cmd, 128, "rm -f %s",filename); + (void) system(remove_cmd); + +} +