Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // gcc -std=c99 -O2 `pkg-config --cflags --libs glib-2.0` bpinger4.c -o bpinger4
- #define _POSIX_C_SOURCE 2
- #define _BSD_SOURCE
- #include <glib.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <stdint.h>
- #include <errno.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <pthread.h>
- #define MAX_HOSTS 60
- #define SCAN_DELAY_MEAN 4*60
- #define SCAN_DELAY_SPREAD 20
- #define SCAN_DELAY_RESCAN 15
- #define HEARTBEAT_DELAY 1391
- #define LOG_TO_FILE
- #define LOG_FILE_NAME "pinger-log.txt"
- struct host {
- gchar *mac;
- gchar *name;
- gchar *shortname;
- gint newstate;
- gint state;
- gint statechange;
- };
- #define HARRAY(a) ((struct host *)((a)->data))
- char *sites[] = {"http://example.com/path/to/log.php"};
- time_t current_time, hb_time;
- int arpping(uint32_t test_nip,
- char *result_mac,
- const char *interface);
- void write2log(const char *format, ...){
- char buf[2048];
- va_list args;
- va_start(args, format);
- vsnprintf(buf, 2048, format, args);
- va_end(args);
- #ifdef LOG_TO_FILE
- struct tm *ltm;
- time_t now;
- time(&now);
- ltm = localtime(&now);
- FILE *fp = fopen(LOG_FILE_NAME, "a+");
- if (NULL == fp) return;
- fprintf(fp, "%4d-%02d-%02d, %02d:%02d:%02d | %s\n",
- ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday,
- ltm->tm_hour, ltm->tm_min, ltm->tm_sec,
- buf);
- fflush(fp);
- fclose(fp);
- #else
- printf("[log] %s\n", buf);
- #endif
- }
- void debugprintf(char *format, ...){
- #ifdef _DEBUG
- char buf[1024];
- va_list args;
- va_start(args, format);
- vsnprintf(buf, 1024, format, args);
- va_end(args);
- printf("[debug] %s\n", buf);
- #endif
- }
- struct worker_data {
- int iface;
- int from;
- int to;
- GArray *hosts;
- pthread_t tid;
- };
- void *worker_thread (void *p) {
- struct worker_data *wd = (struct worker_data *)p;
- char ip[16];
- char mac[20];
- if (wd->iface == 0) {
- for (int j = wd->from; j <= wd->to; j ++ ) {
- sprintf (ip, "192.168.26.%d", j);
- if (0 == arpping (inet_addr (ip), mac, "eth0.1")) {
- for (int k = 0; k < wd->hosts->len; k ++) {
- if (!strncasecmp(mac, HARRAY(wd->hosts)[k].mac, strlen(HARRAY(wd->hosts)[k].mac)))
- HARRAY(wd->hosts)[k].newstate = 1; // online
- }
- }
- }
- } else {
- for (int j = wd->from; j <= wd->to; j ++ ) {
- sprintf (ip, "192.168.1.%d", j);
- if (0 == arpping (inet_addr (ip), mac, "wlan0")) {
- for (int k = 0; k < wd->hosts->len; k ++) {
- if (!strncasecmp(mac, HARRAY(wd->hosts)[k].mac, strlen(HARRAY(wd->hosts)[k].mac)))
- HARRAY(wd->hosts)[k].newstate = 1; // online
- }
- }
- }
- }
- return NULL;
- }
- void do_scan (GArray *hosts) {
- int k;
- for (k = 0; k < hosts->len; k ++){
- HARRAY(hosts)[k].newstate = 0; // set all offline
- }
- struct worker_data wd[10];
- wd[0].iface = 0; wd[0].from = 2; wd[0].to = 50;
- wd[1].iface = 0; wd[1].from = 51; wd[1].to = 100;
- wd[2].iface = 0; wd[2].from = 101; wd[2].to = 150;
- wd[3].iface = 0; wd[3].from = 151; wd[3].to = 200;
- wd[4].iface = 0; wd[4].from = 201; wd[4].to = 254;
- wd[5].iface = 1; wd[5].from = 2; wd[5].to = 50;
- wd[6].iface = 2; wd[6].from = 51; wd[6].to = 100;
- wd[7].iface = 3; wd[7].from = 101; wd[7].to = 150;
- wd[8].iface = 4; wd[8].from = 151; wd[8].to = 200;
- wd[9].iface = 5; wd[9].from = 201; wd[9].to = 254;
- for (k = 0; k < sizeof(wd)/sizeof(struct worker_data); k ++) {
- wd[k].hosts = hosts;
- pthread_create (&wd[k].tid, NULL, &worker_thread, (void *)&wd[k] );
- }
- for (k = 0; k < sizeof(wd)/sizeof(struct worker_data); k ++) {
- pthread_join (wd[k].tid, NULL);
- }
- }
- void send_heartbeat (GArray *hosts) {
- char buf[2048];
- char buf2[100];
- int k;
- for (int site_index = 0; site_index < sizeof(sites)/sizeof(const char *); site_index ++){
- snprintf(buf, 2048, "curl -m 30 -x 127.0.0.1:8888 \"%s?hb&c=%d", sites[site_index], hosts->len);
- for (k = 0; k < hosts->len; k ++){
- snprintf(buf2, 100, "&ls%d=%d", k, HARRAY(hosts)[k].state); // состояние (on/off)
- strcat(buf, buf2);
- snprintf(buf2, 100, "&n%d=%s", k, HARRAY(hosts)[k].shortname); // короткие имена
- strcat(buf, buf2);
- }
- strcat(buf, "\" > /dev/null 2>&1");
- debugprintf("launching %s", buf);
- FILE *fp = popen(buf, "r");
- if (NULL != fp){
- write2log("sent heartbeat to site (%s)", sites[site_index]);
- }else{
- write2log("heartbeat sending failed (%s) (curl error)", sites[site_index]);
- }
- pclose(fp);
- }
- }
- void urlencode(char *dst, int max_dst, const char *src){
- int k, j, len;
- char buf[16];
- strcpy(dst, "");
- j = 0; k = 0;
- len = (int)strlen(src);
- while ((j < len) && (k < max_dst)){
- if (((src[j]>='A')&&(src[j]<='Z')) ||
- ((src[j]>='a')&&(src[j]<='z')) ||
- ((src[j]>='0')&&(src[j]<='9')))
- {
- // not encoding
- snprintf(buf, sizeof(buf), "%c", src[j]); k ++;
- }else{
- snprintf(buf, sizeof(buf), "%%%02X", (unsigned char)src[j]); k += 3;
- }
- strcat(dst, buf);
- j ++;
- }
- }
- void send_to_site (const char *body){
- char buf[2048];
- char encoded_string[2048];
- // здесь было преобразование кодировок через iconv
- urlencode(encoded_string, sizeof(encoded_string), body);
- for (int site_index = 0; site_index < sizeof(sites)/sizeof(const char *); site_index ++){
- snprintf(buf, sizeof(buf),
- "curl -m 30 -x 127.0.0.1:8888 \"%s?t=%s\" > /dev/null 2>/dev/null",
- sites[site_index], encoded_string);
- debugprintf("%s", buf);
- FILE *fp = popen(buf, "r");
- if (NULL == fp){
- // error
- write2log("sending to site (%s) failed. (curl error)", sites[site_index]);
- }else{
- write2log("sent \"%s\" to <site %s>", body, sites[site_index]);
- }
- pclose(fp);
- }
- }
- void inform (GArray *hosts, int hostno){
- time_t ltime;
- struct tm *ltm;
- // чтобы избежать перекодировок, названия месяцев и дней недели задаются в CP1251
- // const char *months[] = {"Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"};
- // const char *dofs[] = {"Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"};
- const char *months[] = {"\xdf\xed\xe2", "\xd4\xe5\xe2", "\xcc\xe0\xf0", "\xc0\xef\xf0",
- "\xcc\xe0\xe9", "\xc8\xfe\xed", "\xc8\xfe\xeb", "\xc0\xe2\xe3",
- "\xd1\xe5\xed", "\xce\xea\xf2", "\xcd\xee\xff", "\xc4\xe5\xea"};
- const char *dofs[] = {"\xc2\xf1", "\xcf\xed", "\xc2\xf2", "\xd1\xf0", "\xd7\xf2", "\xcf\xf2", "\xd1\xe1"};
- time (<ime);
- ltm = localtime(<ime);
- gchar *sms_message = g_strdup_printf ("%s %s %02d:%02d", HARRAY(hosts)[hostno].name,
- HARRAY(hosts)[hostno].state ? "ONLINE" : "OFFLINE", ltm->tm_hour, ltm->tm_min);
- gchar *site_message = g_strdup_printf ("%s%s %02d:%02d %s, %02d %s %04d",
- HARRAY(hosts)[hostno].shortname, HARRAY(hosts)[hostno].state?"ON":"OFF",
- ltm->tm_hour, ltm->tm_min, dofs[ltm->tm_wday], ltm->tm_mday,
- months[ltm->tm_mon], 1900 + ltm->tm_year );
- write2log (sms_message);
- send_to_site (site_message);
- g_free (sms_message);
- g_free (site_message);
- }
- int single_instance(){
- char buf[1024];
- int count;
- snprintf(buf, sizeof(buf), "pgrep -c `basename $(readlink /proc/%d/exe)`", getpid());
- FILE *pp = popen(buf, "r");
- fscanf(pp, "%d", &count);
- pclose(pp);
- if (count == 1) return 1; else return 0;
- }
- void die (const char *msg) {
- fprintf (stderr, "%s", msg);
- exit (1);
- }
- int main(int argc, char *argv[]){
- int scan_delay_mean = (SCAN_DELAY_MEAN)*1000; // ms
- int scan_delay_spread = (SCAN_DELAY_SPREAD)*1000; // ms
- int scan_delay_rescan = (SCAN_DELAY_RESCAN)*1000; // ms
- int hb_delay = (HEARTBEAT_DELAY); // sec
- int k;
- struct tm *ltm;
- /* FIXME: ensure single instance on router
- if (!single_instance()){
- printf("other copy running.\n");
- return 0;
- }
- */
- // задаем список хостов
- // их можно было бы читать из файла, но в моем случае это совсем не нужно
- GArray *hosts = g_array_sized_new (FALSE, TRUE, sizeof (struct host), 20);
- struct host h;
- memset (&h, 0, sizeof (struct host));
- h.name = g_strdup ("longname1");
- h.shortname = g_strdup ("s1");
- h.mac = g_strdup ("XX:XX:XX:XX:XX:XX");
- g_array_append_val (hosts, h);
- h.name = g_strdup ("longname1 (another)");
- h.shortname = g_strdup ("s1");
- h.mac = g_strdup ("00:AB:CD:EF:12:34");
- g_array_append_val (hosts, h);
- h.name = g_strdup ("longname2");
- h.shortname = g_strdup ("s2");
- h.mac = g_strdup ("00:XX:XX:XX:XX:XX");
- g_array_append_val (hosts, h);
- h.name = g_strdup ("longname3");
- h.shortname = g_strdup ("s3");
- h.mac = g_strdup ("00:XX:XX:XX:XX:XX");
- g_array_append_val (hosts, h);
- // =============================================================================================
- do_scan (hosts); // определяем текущие значения
- for (k = 0; k < hosts->len; k ++) HARRAY(hosts)[k].state = HARRAY(hosts)[k].newstate;
- time(¤t_time);
- ltm = localtime(¤t_time);
- hb_time = current_time;
- send_heartbeat (hosts);
- {
- gchar *buf = g_strdup_printf ("pinger started %02d:%02d", ltm->tm_hour, ltm->tm_min);
- write2log(buf);
- send_to_site(buf);
- g_free (buf);
- }
- do {
- for (k = 0; k < hosts->len; k ++){
- debugprintf ("host[%d].state=%d ", k, HARRAY(hosts)[k].state);
- }
- // вычисляем задержку между сканированиями
- int time_to_wait = scan_delay_mean +
- (int)( (double)scan_delay_spread * rand() / (double)RAND_MAX );
- do_scan (hosts); // сканируем сеть
- // предотвращение срабатывания на дребезг -- случайного выпадения
- // компьютера из сети или наоборот, случайного появления
- int changes = 0; // флаг
- for (k = 0; k < hosts->len; k ++){
- if (HARRAY(hosts)[k].newstate != HARRAY(hosts)[k].state){
- changes = 1; // чье-то состояние изменилось
- HARRAY(hosts)[k].statechange ++;
- }else{
- HARRAY(hosts)[k].statechange = 0;
- }
- }
- if (changes > 0) { // чье-то состояние изменилось
- time_to_wait = scan_delay_rescan; // уменьшаем задержку
- }
- changes = 0;
- for (k = 0; k < hosts->len; k ++) {
- if (HARRAY(hosts)[k].statechange >= 2) {
- HARRAY(hosts)[k].statechange = 0;
- HARRAY(hosts)[k].state = HARRAY(hosts)[k].newstate;
- inform (hosts, k); // сообщить кому следует
- changes = 1;
- }
- }
- // если у одного из хостов меняется состояние
- // (после коррекции дребезга), отсылаем уведомление на сайт
- if (changes > 0) send_heartbeat (hosts);
- while (time_to_wait > 1010){
- g_usleep (G_USEC_PER_SEC * 1.01f);
- time_to_wait -= 1010;
- time (¤t_time);
- debugprintf ("time_to_wait = %d, next hb in %d sec", time_to_wait, hb_time + hb_delay - current_time);
- if ((int)(current_time - hb_time) > hb_delay){
- send_heartbeat (hosts);
- hb_time = current_time;
- }
- }
- debugprintf ("waiting complete\n");
- // секундная задержка (на на случай если предыдущий цикл не отработал
- g_usleep (G_USEC_PER_SEC);
- } while (1);
- // вычистить память
- for (k = 0; k < hosts->len; k ++) {
- g_free (HARRAY(hosts)[k].mac);
- g_free (HARRAY(hosts)[k].name);
- g_free (HARRAY(hosts)[k].shortname);
- }
- g_array_unref (hosts);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement