Advertisement
ibragimovrinat

bpinger.c

Aug 12th, 2012
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.37 KB | None | 0 0
  1. // gcc -std=c99 -O2 `pkg-config --cflags --libs glib-2.0` bpinger4.c -o bpinger4
  2.  
  3. #define _POSIX_C_SOURCE 2
  4. #define _BSD_SOURCE
  5.  
  6. #include <glib.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <sys/types.h>
  11. #include <unistd.h>
  12. #include <stdint.h>
  13. #include <errno.h>
  14. #include <sys/socket.h>
  15. #include <netinet/in.h>
  16. #include <arpa/inet.h>
  17. #include <pthread.h>
  18.  
  19.  
  20. #define    MAX_HOSTS    60
  21.  
  22. #define SCAN_DELAY_MEAN     4*60
  23. #define SCAN_DELAY_SPREAD   20
  24. #define SCAN_DELAY_RESCAN   15
  25.  
  26. #define HEARTBEAT_DELAY     1391
  27.  
  28. #define    LOG_TO_FILE
  29. #define    LOG_FILE_NAME        "pinger-log.txt"
  30.  
  31.  
  32. struct host {
  33.     gchar *mac;
  34.     gchar *name;
  35.     gchar *shortname;
  36.     gint   newstate;
  37.     gint   state;
  38.     gint   statechange;
  39. };
  40.  
  41. #define HARRAY(a)   ((struct host *)((a)->data))
  42.  
  43. char *sites[] = {"http://example.com/path/to/log.php"};
  44.  
  45. time_t  current_time, hb_time;
  46.  
  47. int arpping(uint32_t test_nip,
  48.         char *result_mac,
  49.         const char *interface);
  50.  
  51. void    write2log(const char *format, ...){
  52.     char buf[2048];
  53.     va_list args;
  54.     va_start(args, format);
  55.     vsnprintf(buf, 2048, format, args);
  56.     va_end(args);
  57.  
  58. #ifdef    LOG_TO_FILE
  59.     struct tm    *ltm;
  60.     time_t        now;
  61.  
  62.     time(&now);
  63.     ltm = localtime(&now);
  64.  
  65.     FILE *fp = fopen(LOG_FILE_NAME, "a+");
  66.     if (NULL == fp) return;
  67.  
  68.     fprintf(fp, "%4d-%02d-%02d, %02d:%02d:%02d | %s\n",
  69.         ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday,
  70.         ltm->tm_hour, ltm->tm_min, ltm->tm_sec,
  71.         buf);
  72.  
  73.     fflush(fp);
  74.     fclose(fp);
  75. #else
  76.     printf("[log] %s\n", buf);
  77. #endif
  78. }
  79.  
  80. void    debugprintf(char *format, ...){
  81. #ifdef _DEBUG
  82.     char buf[1024];
  83.     va_list args;
  84.     va_start(args, format);
  85.     vsnprintf(buf, 1024, format, args);
  86.     va_end(args);
  87.  
  88.     printf("[debug] %s\n", buf);
  89. #endif
  90. }
  91.  
  92. struct worker_data {
  93.     int iface;
  94.     int from;
  95.     int to;
  96.     GArray *hosts;
  97.     pthread_t tid;
  98. };
  99.  
  100. void *worker_thread (void *p) {
  101.     struct worker_data *wd = (struct worker_data *)p;
  102.     char ip[16];
  103.     char mac[20];
  104.     if (wd->iface == 0) {
  105.         for (int j = wd->from; j <= wd->to; j ++ ) {
  106.             sprintf (ip, "192.168.26.%d", j);
  107.             if (0 == arpping (inet_addr (ip), mac, "eth0.1")) {
  108.                 for (int k = 0; k < wd->hosts->len; k ++) {
  109.                     if (!strncasecmp(mac, HARRAY(wd->hosts)[k].mac, strlen(HARRAY(wd->hosts)[k].mac)))
  110.                         HARRAY(wd->hosts)[k].newstate = 1;    // online
  111.                 }
  112.             }
  113.         }
  114.     } else {
  115.         for (int j = wd->from; j <= wd->to; j ++ ) {
  116.             sprintf (ip, "192.168.1.%d", j);
  117.             if (0 == arpping (inet_addr (ip), mac, "wlan0")) {
  118.                 for (int k = 0; k < wd->hosts->len; k ++) {
  119.                     if (!strncasecmp(mac, HARRAY(wd->hosts)[k].mac, strlen(HARRAY(wd->hosts)[k].mac)))
  120.                         HARRAY(wd->hosts)[k].newstate = 1;    // online
  121.                 }
  122.             }
  123.         }
  124.     }
  125.     return NULL;
  126. }
  127.  
  128. void    do_scan (GArray *hosts) {
  129.     int        k;
  130.  
  131.     for (k = 0; k < hosts->len; k ++){
  132.         HARRAY(hosts)[k].newstate = 0;                    // set all offline
  133.     }
  134.  
  135.     struct worker_data wd[10];
  136.     wd[0].iface = 0;    wd[0].from = 2;    wd[0].to = 50;
  137.     wd[1].iface = 0;    wd[1].from = 51;   wd[1].to = 100;
  138.     wd[2].iface = 0;    wd[2].from = 101;  wd[2].to = 150;
  139.     wd[3].iface = 0;    wd[3].from = 151;  wd[3].to = 200;
  140.     wd[4].iface = 0;    wd[4].from = 201;  wd[4].to = 254;
  141.  
  142.     wd[5].iface = 1;    wd[5].from = 2;    wd[5].to = 50;
  143.     wd[6].iface = 2;    wd[6].from = 51;   wd[6].to = 100;
  144.     wd[7].iface = 3;    wd[7].from = 101;  wd[7].to = 150;
  145.     wd[8].iface = 4;    wd[8].from = 151;  wd[8].to = 200;
  146.     wd[9].iface = 5;    wd[9].from = 201;  wd[9].to = 254;
  147.  
  148.     for (k = 0; k < sizeof(wd)/sizeof(struct worker_data); k ++) {
  149.         wd[k].hosts = hosts;
  150.         pthread_create (&wd[k].tid, NULL, &worker_thread, (void *)&wd[k] );
  151.     }
  152.  
  153.     for (k = 0; k < sizeof(wd)/sizeof(struct worker_data); k ++) {
  154.         pthread_join (wd[k].tid, NULL);
  155.     }
  156. }
  157.  
  158. void    send_heartbeat (GArray *hosts) {
  159.     char buf[2048];
  160.     char buf2[100];
  161.     int    k;
  162.  
  163.     for (int site_index = 0; site_index < sizeof(sites)/sizeof(const char *); site_index ++){
  164.  
  165.         snprintf(buf, 2048, "curl -m 30 -x 127.0.0.1:8888 \"%s?hb&c=%d", sites[site_index], hosts->len);
  166.         for (k = 0; k < hosts->len; k ++){
  167.             snprintf(buf2, 100, "&ls%d=%d", k, HARRAY(hosts)[k].state);        // состояние (on/off)
  168.             strcat(buf, buf2);
  169.             snprintf(buf2, 100, "&n%d=%s", k, HARRAY(hosts)[k].shortname);        // короткие имена
  170.             strcat(buf, buf2);
  171.         }
  172.         strcat(buf, "\" > /dev/null 2>&1");
  173.  
  174.         debugprintf("launching %s", buf);
  175.  
  176.         FILE *fp = popen(buf, "r");
  177.         if (NULL != fp){
  178.             write2log("sent heartbeat to site (%s)", sites[site_index]);
  179.         }else{
  180.             write2log("heartbeat sending failed (%s) (curl error)", sites[site_index]);
  181.         }
  182.         pclose(fp);
  183.     }
  184. }
  185.  
  186.  
  187. void    urlencode(char *dst, int max_dst, const char *src){
  188.     int        k, j, len;
  189.     char  buf[16];
  190.     strcpy(dst, "");
  191.     j = 0; k = 0;
  192.     len = (int)strlen(src);
  193.     while ((j < len) && (k < max_dst)){
  194.         if (((src[j]>='A')&&(src[j]<='Z')) ||
  195.             ((src[j]>='a')&&(src[j]<='z')) ||
  196.             ((src[j]>='0')&&(src[j]<='9')))
  197.         {
  198.             // not encoding
  199.             snprintf(buf, sizeof(buf), "%c", src[j]); k ++;
  200.         }else{
  201.             snprintf(buf, sizeof(buf), "%%%02X", (unsigned char)src[j]); k += 3;
  202.  
  203.         }
  204.         strcat(dst, buf);
  205.         j ++;
  206.     }
  207. }
  208.  
  209. void    send_to_site (const char *body){
  210.     char    buf[2048];
  211.     char    encoded_string[2048];
  212.  
  213.     // здесь было преобразование кодировок через iconv
  214.  
  215.     urlencode(encoded_string, sizeof(encoded_string), body);
  216.  
  217.     for (int site_index = 0; site_index < sizeof(sites)/sizeof(const char *); site_index ++){
  218.  
  219.         snprintf(buf, sizeof(buf),
  220.             "curl -m 30 -x 127.0.0.1:8888 \"%s?t=%s\" > /dev/null 2>/dev/null",
  221.             sites[site_index], encoded_string);
  222.         debugprintf("%s", buf);
  223.  
  224.         FILE *fp = popen(buf, "r");
  225.         if (NULL == fp){
  226.             // error
  227.             write2log("sending to site (%s) failed. (curl error)", sites[site_index]);
  228.         }else{
  229.             write2log("sent \"%s\" to <site %s>", body, sites[site_index]);
  230.         }
  231.         pclose(fp);
  232.     }
  233. }
  234.  
  235.  
  236. void    inform (GArray *hosts, int hostno){
  237.     time_t    ltime;
  238.     struct    tm *ltm;
  239.  
  240.     // чтобы избежать перекодировок, названия месяцев и дней недели задаются в CP1251
  241.     // const char    *months[] = {"Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"};
  242.     // const char  *dofs[] = {"Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"};
  243.  
  244.     const char *months[] = {"\xdf\xed\xe2", "\xd4\xe5\xe2", "\xcc\xe0\xf0", "\xc0\xef\xf0",
  245.                             "\xcc\xe0\xe9", "\xc8\xfe\xed", "\xc8\xfe\xeb", "\xc0\xe2\xe3",
  246.                             "\xd1\xe5\xed", "\xce\xea\xf2", "\xcd\xee\xff", "\xc4\xe5\xea"};
  247.     const char *dofs[] =   {"\xc2\xf1", "\xcf\xed", "\xc2\xf2", "\xd1\xf0", "\xd7\xf2", "\xcf\xf2", "\xd1\xe1"};
  248.  
  249.     time (&ltime);
  250.     ltm = localtime(&ltime);
  251.  
  252.     gchar *sms_message = g_strdup_printf ("%s %s %02d:%02d", HARRAY(hosts)[hostno].name,
  253.         HARRAY(hosts)[hostno].state ? "ONLINE" : "OFFLINE",    ltm->tm_hour, ltm->tm_min);
  254.  
  255.     gchar *site_message = g_strdup_printf ("%s%s %02d:%02d %s, %02d %s %04d",
  256.         HARRAY(hosts)[hostno].shortname, HARRAY(hosts)[hostno].state?"ON":"OFF",
  257.         ltm->tm_hour, ltm->tm_min,    dofs[ltm->tm_wday], ltm->tm_mday,
  258.         months[ltm->tm_mon], 1900 + ltm->tm_year );
  259.  
  260.     write2log (sms_message);
  261.     send_to_site (site_message);
  262.     g_free (sms_message);
  263.     g_free (site_message);
  264. }
  265.  
  266. int single_instance(){
  267.     char buf[1024];
  268.     int count;
  269.     snprintf(buf, sizeof(buf), "pgrep -c `basename $(readlink /proc/%d/exe)`", getpid());
  270.     FILE *pp = popen(buf, "r");
  271.     fscanf(pp, "%d", &count);
  272.     pclose(pp);
  273.  
  274.     if (count == 1) return 1; else return 0;
  275. }
  276.  
  277. void die (const char *msg) {
  278.     fprintf (stderr, "%s", msg);
  279.     exit (1);
  280. }
  281.  
  282.  
  283. int main(int argc, char *argv[]){
  284.  
  285.     int        scan_delay_mean        = (SCAN_DELAY_MEAN)*1000;        // ms
  286.     int        scan_delay_spread    = (SCAN_DELAY_SPREAD)*1000;        // ms
  287.     int        scan_delay_rescan    = (SCAN_DELAY_RESCAN)*1000;        // ms
  288.  
  289.     int        hb_delay            = (HEARTBEAT_DELAY);            // sec
  290.  
  291.     int     k;
  292.  
  293.     struct    tm    *ltm;
  294.  
  295. /* FIXME: ensure single instance on router
  296.     if (!single_instance()){
  297.         printf("other copy running.\n");
  298.         return 0;
  299.     }
  300. */
  301.  
  302.     // задаем список хостов
  303.     // их можно было бы читать из файла, но в моем случае это совсем не нужно
  304.  
  305.     GArray *hosts = g_array_sized_new (FALSE, TRUE, sizeof (struct host), 20);
  306.  
  307.     struct host h;
  308.     memset (&h, 0, sizeof (struct host));
  309.  
  310.     h.name =      g_strdup ("longname1");
  311.     h.shortname = g_strdup ("s1");
  312.     h.mac =       g_strdup ("XX:XX:XX:XX:XX:XX");
  313.     g_array_append_val (hosts, h);
  314.  
  315.     h.name =      g_strdup ("longname1 (another)");
  316.     h.shortname = g_strdup ("s1");
  317.     h.mac =       g_strdup ("00:AB:CD:EF:12:34");
  318.     g_array_append_val (hosts, h);
  319.  
  320.     h.name =      g_strdup ("longname2");
  321.     h.shortname = g_strdup ("s2");
  322.     h.mac =       g_strdup ("00:XX:XX:XX:XX:XX");
  323.     g_array_append_val (hosts, h);
  324.  
  325.     h.name =      g_strdup ("longname3");
  326.     h.shortname = g_strdup ("s3");
  327.     h.mac =       g_strdup ("00:XX:XX:XX:XX:XX");
  328.     g_array_append_val (hosts, h);
  329.  
  330.     // =============================================================================================
  331.  
  332.     do_scan (hosts);    // определяем текущие значения
  333.     for (k = 0; k < hosts->len; k ++) HARRAY(hosts)[k].state = HARRAY(hosts)[k].newstate;
  334.  
  335.     time(&current_time);
  336.     ltm = localtime(&current_time);
  337.     hb_time = current_time;
  338.     send_heartbeat (hosts);
  339.  
  340.     {
  341.         gchar *buf = g_strdup_printf ("pinger started %02d:%02d", ltm->tm_hour, ltm->tm_min);
  342.         write2log(buf);
  343.         send_to_site(buf);
  344.         g_free (buf);
  345.     }
  346.  
  347.     do {
  348.         for (k = 0; k < hosts->len; k ++){
  349.             debugprintf ("host[%d].state=%d   ", k, HARRAY(hosts)[k].state);
  350.         }
  351.  
  352.         // вычисляем задержку между сканированиями
  353.         int time_to_wait = scan_delay_mean +
  354.             (int)( (double)scan_delay_spread * rand() / (double)RAND_MAX );
  355.  
  356.         do_scan (hosts);        // сканируем сеть
  357.  
  358.         // предотвращение срабатывания на дребезг -- случайного выпадения
  359.         // компьютера из сети или наоборот, случайного появления
  360.         int changes = 0;                    // флаг
  361.         for (k = 0; k < hosts->len; k ++){
  362.             if (HARRAY(hosts)[k].newstate != HARRAY(hosts)[k].state){
  363.                 changes = 1;                    // чье-то состояние изменилось
  364.                 HARRAY(hosts)[k].statechange ++;
  365.             }else{
  366.                 HARRAY(hosts)[k].statechange = 0;
  367.             }
  368.         }
  369.  
  370.         if (changes > 0) {                       // чье-то состояние изменилось
  371.             time_to_wait = scan_delay_rescan;    // уменьшаем задержку
  372.         }
  373.  
  374.         changes = 0;
  375.         for (k = 0; k < hosts->len; k ++) {
  376.             if (HARRAY(hosts)[k].statechange >= 2) {
  377.                 HARRAY(hosts)[k].statechange = 0;
  378.                 HARRAY(hosts)[k].state = HARRAY(hosts)[k].newstate;
  379.                 inform (hosts, k);                            // сообщить кому следует
  380.                 changes = 1;
  381.             }
  382.         }
  383.         // если у одного из хостов меняется состояние
  384.         // (после коррекции дребезга), отсылаем уведомление на сайт
  385.         if (changes > 0) send_heartbeat (hosts);
  386.  
  387.         while (time_to_wait > 1010){
  388.             g_usleep (G_USEC_PER_SEC * 1.01f);
  389.             time_to_wait -= 1010;
  390.  
  391.             time (&current_time);
  392.             debugprintf ("time_to_wait = %d, next hb in %d sec", time_to_wait, hb_time + hb_delay - current_time);
  393.  
  394.             if ((int)(current_time - hb_time) > hb_delay){
  395.                 send_heartbeat (hosts);
  396.                 hb_time = current_time;
  397.             }
  398.         }
  399.  
  400.         debugprintf ("waiting complete\n");
  401.  
  402.         // секундная задержка (на на случай если предыдущий цикл не отработал
  403.         g_usleep (G_USEC_PER_SEC);
  404.     } while (1);
  405.  
  406.     // вычистить память
  407.     for (k = 0; k < hosts->len; k ++) {
  408.         g_free (HARRAY(hosts)[k].mac);
  409.         g_free (HARRAY(hosts)[k].name);
  410.         g_free (HARRAY(hosts)[k].shortname);
  411.     }
  412.     g_array_unref (hosts);
  413.  
  414.     return 0;
  415. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement