Advertisement
arcx33

Nagios NCSA replacement

Dec 3rd, 2011
1,221
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.46 KB | None | 0 0
  1. /* vim:ts=4
  2. */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <signal.h>
  8. #include <sys/socket.h>
  9. #include <pthread.h>
  10. #include <sys/types.h>
  11. #include <arpa/inet.h>
  12. #include <unistd.h>
  13.  
  14. const char *VERSION = "Nagios Proxy (http://madebyryan.blogspot.com/) Build: " __DATE__ " at " __TIME__;
  15.  
  16. #define NSCA_PORT 5667
  17. /*
  18. #define DEBUGA  1
  19. */
  20. void listen_mode(void);
  21. void broadcast_mode(void);
  22. void *listen_thread(void *socket_int);
  23. void *pipeout_thread(void *NotUsed);
  24. void *broadcast_thread(void *socket_int);
  25. int broadcast_connect(void);
  26. void *proxy_health_thread(void *NotUsed);
  27. static void print_timestamp(FILE *output);
  28.  
  29. void queue_add(const char *buffer);
  30. const char *queue_remove(void);
  31.  
  32. int sock;
  33. struct sockaddr_in bindaddr;
  34. int is_listenmode = 1;
  35. char *destination;
  36.  
  37. pthread_mutex_t queue_mutex;
  38.  
  39. int main(int argc, char **argv)
  40. {
  41.     pthread_t thread;
  42.     int rv;
  43.  
  44.     destination = argv[1];
  45.     if (argc == 1)
  46.         is_listenmode = 1;
  47.     else
  48.         is_listenmode = 0;
  49.  
  50.     signal(SIGPIPE, SIG_IGN);
  51.  
  52.     print_timestamp(stderr);
  53.     fprintf(stderr, "Startup in %s mode\n", is_listenmode ? "LISTEN" : "BROADCAST");
  54.  
  55.     rv = pthread_create(&thread, NULL, proxy_health_thread, NULL);
  56.     if (rv != 0) {
  57.         print_timestamp(stderr);
  58.         fprintf(stderr, "Creating health thread failed: %d\n", rv);
  59.     } else {
  60.        rv =  pthread_detach(thread);
  61.         if (rv != 0) {
  62.             print_timestamp(stderr);
  63.             fprintf(stderr, "Failed to detach health thread: %d\n", rv);
  64.         }
  65.     }
  66.  
  67.     /*
  68.      * Setup listening socket
  69.      */
  70.     if (is_listenmode)
  71.         listen_mode();
  72.     else
  73.         broadcast_mode();
  74.  
  75.     return 0;
  76. }
  77.  
  78. void listen_mode(void)
  79. {
  80.     pthread_t thread;
  81.     int i, client, rv;
  82.     socklen_t addrlen;
  83.     struct sockaddr_in clientaddr;
  84.  
  85.     pthread_mutex_init(&queue_mutex, NULL);
  86.     rv = pthread_create(&thread, NULL, pipeout_thread, NULL);
  87.     if (rv != 0) {
  88.         print_timestamp(stderr);
  89.         fprintf(stderr, "Creating pipeout thread failed: %d\n", rv);
  90.     } else {
  91.        rv =  pthread_detach(thread);
  92.         if (rv != 0) {
  93.             print_timestamp(stderr);
  94.             fprintf(stderr, "Failed to detach pipeout thread: %d\n", rv);
  95.         }
  96.     }
  97.  
  98.  
  99.     sock = socket(PF_INET, SOCK_STREAM, 0);
  100.     if (sock == -1) {
  101.         print_timestamp(stderr);
  102.         fprintf(stderr, "failed to create socket at %s:%d\n",
  103.                 __FILE__, __LINE__);
  104.         exit(0);
  105.     }
  106.  
  107.     i = 1;
  108.     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)) < 0) {
  109.         print_timestamp(stderr);
  110.         fprintf(stderr, "setsockopt failed: %s\n", strerror(errno));
  111.     }
  112.  
  113.     memset(&bindaddr, 0, sizeof(struct sockaddr_in));
  114.     bindaddr.sin_family = PF_INET;
  115.     bindaddr.sin_port = htons(NSCA_PORT);
  116.     bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  117.  
  118.     if (bind(sock, (struct sockaddr *)&bindaddr,
  119.             sizeof(struct sockaddr_in)) == -1) {
  120.         print_timestamp(stderr);
  121.         fprintf(stderr, "bind failed: %s", strerror(errno));
  122.         exit(1);
  123.     }
  124.  
  125.     if (listen(sock, 5) == -1) {
  126.         print_timestamp(stderr);
  127.         fprintf(stderr, "listen failed: %s\n", strerror(errno));
  128.         exit(0);
  129.     }
  130.  
  131.     while (1) {
  132.         addrlen = sizeof(struct sockaddr_in);
  133.         memset(&clientaddr, 0, sizeof(struct sockaddr));
  134.         client = accept(sock, (struct sockaddr *)&clientaddr, &addrlen);
  135.         if (client == -1) {
  136.             print_timestamp(stderr);
  137.             fprintf(stderr, "accept failed: %s\n", strerror(errno));
  138.         } else {
  139.             rv = pthread_create(&thread, NULL, listen_thread, (void *)client);
  140.             if (rv != 0) {
  141.                 print_timestamp(stderr);
  142.                 fprintf(stderr, "Creating listen thread failed: %d\n", rv);
  143.                 close(sock);
  144.             } else {
  145.                rv =  pthread_detach(thread);
  146.                 if (rv != 0) {
  147.                     print_timestamp(stderr);
  148.                     fprintf(stderr, "Failed to detach listen thread: %d\n", rv);
  149.                 }
  150.             }
  151.         }
  152.     }
  153. }
  154.  
  155. void broadcast_mode(void)
  156. {
  157.     FILE *input;
  158.     char buffer[16342], *retstr;
  159.     int i, rv;
  160.     pthread_t thread;
  161.  
  162.     input = fopen("nagios-remote.cmd", "r");
  163.     if (input == NULL) {
  164.         print_timestamp(stderr);
  165.         fprintf(stderr, "Failed to open nagios-remote.cmd\n");
  166.         exit(1);
  167.     }
  168.  
  169.     rv = pthread_create(&thread, NULL, broadcast_thread, NULL);
  170.     if (rv != 0) {
  171.         print_timestamp(stderr);
  172.         fprintf(stderr, "Creating broadcast thread failed: %d\n", rv);
  173.     } else {
  174.        rv =  pthread_detach(thread);
  175.         if (rv != 0) {
  176.             print_timestamp(stderr);
  177.             fprintf(stderr, "Failed to detach broadcast thread: %d\n", rv);
  178.         }
  179.     }
  180.  
  181.     while (1) {
  182.         retstr = fgets(buffer, 16342, input);
  183.         if (retstr == NULL) {
  184.             clearerr(input);
  185.             usleep(1000);
  186.             continue;
  187.         }
  188.         i = strlen(buffer);
  189.         buffer[i] = 0;
  190.        
  191.         /*
  192.          * Skip obviously wrong plugin output, helps buggy installs
  193.          * add everything else for processing
  194.          */
  195.         if (strstr(buffer, "/bin/ping") == NULL)
  196.             queue_add(buffer);
  197.     }
  198. }
  199.  
  200. void *broadcast_thread(void *socket_int)
  201. {
  202.     int sock, sendret;
  203.     const char *data;
  204.  
  205. restart_broadcast:
  206.     do {
  207.         sock = broadcast_connect();
  208.         if (sock == -1)
  209.             usleep(1000);
  210.     } while (sock == -1);
  211.  
  212.     do {
  213.         data = queue_remove();
  214.         while (data == NULL) {
  215.             usleep(1000);
  216.             data = queue_remove();
  217.         }
  218.         sendret = send(sock, data, strlen(data), 0);
  219.         if (sendret == -1) {
  220.             print_timestamp(stderr);
  221.             fprintf(stderr, "Disconnected : %s\n", strerror(errno));
  222.             goto restart_broadcast;
  223.         }
  224.        
  225.     } while (1);
  226.  
  227. }
  228.  
  229. void *listen_thread(void *socket_int)
  230. {
  231.     int client;
  232.     char buffer[16348], *endofbuffer;
  233.     int datalen, datapos;
  234.     struct sockaddr_in peer;
  235.     socklen_t peerlen;
  236.     char *inetret;
  237.     char clientname[64];
  238.  
  239.     client = (int)socket_int;
  240.     datapos = 0;
  241.     buffer[0] = 0;
  242.  
  243.     peerlen = sizeof(struct sockaddr_in);
  244.     if (getpeername(client, (struct sockaddr *)&peer, &peerlen) == -1) {
  245.         snprintf(clientname, 1024, "Unknown");
  246.     } else {
  247.         inetret = inet_ntoa(peer.sin_addr);
  248.         strncpy(clientname, inetret, 64);
  249.     }
  250.  
  251.     do {
  252.         datalen = recv(client, buffer+datapos, 16348-datapos, 0);
  253.  
  254.         if (datalen > 0) {
  255.             datapos += datalen;
  256.             buffer[datapos] = 0;
  257.         }
  258.    
  259.         if (datalen <= 0) {
  260.             if (errno != 0) {
  261.                 print_timestamp(stderr);
  262.                 fprintf(stderr, "Client (%s) Disconnected %d: %s\n", clientname,
  263.                         errno, strerror(errno));
  264.             }
  265.             close(client);
  266.             return NULL;
  267.         }
  268.  
  269.         while ((endofbuffer = strchr(buffer, '\n')) != NULL) {
  270.             *endofbuffer = 0;
  271.             queue_add(buffer);
  272. #ifdef DEBUGA
  273.             print_timestamp(stderr);
  274.             fprintf(stderr, "--- buffer: '%s'\n datapos(%d) endofbuffer(%d)\n", buffer, datapos, endofbuffer-buffer);
  275. #endif
  276.             memmove(buffer, endofbuffer+1, datapos - (endofbuffer-buffer));
  277.             datapos -= (endofbuffer-buffer)+1;
  278.         }
  279.     } while(1);
  280. }
  281.  
  282. void *pipeout_thread(void *NotUsed)
  283. {
  284.     const char *data;
  285.     FILE *dataout;
  286.     int do_len;
  287. #ifdef DEBUGA
  288.     int se_len;
  289. #endif
  290.  
  291.     dataout = fopen("nagios.cmd", "w");
  292.     if (dataout == NULL) {
  293.         print_timestamp(stderr);
  294.         fprintf(stderr, "Failed to open nagios.cmd for output\n");
  295.         exit(1);
  296.     }
  297.  
  298.     do {
  299.         data = queue_remove();
  300.         while (data == NULL) {
  301.             if(dataout != NULL)
  302.                 fclose(dataout);
  303.             dataout = NULL;
  304.             usleep(1000);
  305.             data = queue_remove();
  306.         }
  307. restart_outwrite:
  308.         if (dataout == NULL) {
  309.             dataout = fopen("nagios.cmd", "w");
  310.             if (dataout == NULL) {
  311.                 print_timestamp(stderr);
  312.                 fprintf(stderr, "Failed to open nagios.cmd for output\n");
  313.                 exit(1);
  314.             }
  315.         }
  316.         do_len = fprintf(dataout, "[%lu] %s\n", time(NULL), data);
  317.         /*se_len = fprintf(stderr, "[%u] %s\n", time(NULL), data);
  318.     printf("Wrote dataout(%d) stderr(%d)\n", do_len, se_len);*/
  319.         if (do_len == 0) {
  320.             fclose(dataout);
  321.             dataout = NULL;
  322.             goto restart_outwrite;
  323.         }
  324.     } while (1);
  325. }
  326.  
  327. int queue_head = 0, queue_tail = 0;
  328. int queue_size = 0;
  329. int queue_additions = 0, queue_bytes = 0;
  330. char queue_data[4096][1024];
  331.  
  332. void queue_add(const char *buffer)
  333. {
  334.     int is_added = 0;
  335.     int slen, rv;
  336.  
  337. #ifdef DEBUGA
  338.     fprintf(stderr, "Adding(%d): \"%s\"\n", queue_size, buffer);
  339. #endif
  340.  
  341.     rv = pthread_mutex_lock(&queue_mutex);
  342.     if (rv != 0) {
  343.         print_timestamp(stderr);
  344.         fprintf(stderr, "Failed to lock mutex in queue_add(): %d\n", rv);
  345.         return;
  346.     }
  347.  
  348.     if ((queue_tail+1) % 4096 != queue_head) {
  349.         slen = strlen(buffer);
  350.         memcpy(queue_data[queue_tail], buffer, slen+1);
  351.         ++queue_tail;
  352.         queue_tail %= 4096;
  353.         is_added = 1;
  354.         ++queue_size;
  355.         ++queue_additions;
  356.         queue_bytes += slen;
  357.     }
  358.  
  359.     rv = pthread_mutex_unlock(&queue_mutex);
  360.     if (rv != 0) {
  361.         print_timestamp(stderr);
  362.         fprintf(stderr, "Failed to unlock mutex in queue_add(): %d\n", rv);
  363.     }
  364. }
  365.  
  366. const char *queue_remove(void)
  367. {
  368.     const char *retstr;
  369.     int rv;
  370.  
  371.     rv = pthread_mutex_lock(&queue_mutex);
  372.     if (rv != 0) {
  373.         print_timestamp(stderr);
  374.         fprintf(stderr, "Failed to lock mutex in queue_remove(): %d\n", rv);
  375.         return NULL;
  376.     }
  377.  
  378.     if (queue_head != queue_tail) {
  379.         retstr = queue_data[queue_head];
  380.         ++queue_head;
  381.         queue_head %= 4096;
  382.     --queue_size;
  383. #ifdef DEBUGA
  384.         fprintf(stderr, "Removing(%d): \"%s\"\n", queue_size, retstr);
  385. #endif
  386.     } else
  387.         retstr = NULL;
  388.  
  389.     rv = pthread_mutex_unlock(&queue_mutex);
  390.     if (rv != 0) {
  391.         print_timestamp(stderr);
  392.         fprintf(stderr, "Failed to unlock mutex in queue_remove(): %d\n", rv);
  393.     }
  394.  
  395.     return retstr;
  396. }
  397.  
  398.  
  399. int broadcast_connect(void)
  400. {
  401.     int i, sock, client;
  402.  
  403. restart_connection:
  404.     sock = socket(PF_INET, SOCK_STREAM, 0);
  405.     if (sock == -1) {
  406.         print_timestamp(stderr);
  407.         fprintf(stderr, "failed to create socket at %s:%d\n", __FILE__,
  408.                 __LINE__);
  409.         exit(0);
  410.     }
  411.  
  412.     i = 1;
  413.     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)) < 0) {
  414.         print_timestamp(stderr);
  415.         fprintf(stderr, "setsockopt failed: %s\n", strerror(errno));
  416.     }
  417.  
  418.     memset(&bindaddr, 0, sizeof(struct sockaddr_in));
  419.     bindaddr.sin_family = PF_INET;
  420.     bindaddr.sin_port = htons(NSCA_PORT);
  421.     bindaddr.sin_addr.s_addr = inet_addr(destination);
  422.     client = connect(sock, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in));
  423.     if (client == -1) {
  424.         print_timestamp(stderr);
  425.         fprintf(stderr, "connect failed: %s:%d - %s\n", destination, NSCA_PORT,
  426.                 strerror(errno));
  427.         close(sock);
  428.         usleep(1000);
  429.         goto restart_connection;
  430.     }
  431.     return sock;
  432.  
  433. }
  434.  
  435. void *proxy_health_thread(void *NotUsed)
  436. {
  437.     char hostname[128];
  438.     char buffer[1024];
  439.  
  440.     gethostname(hostname, 128);
  441.  
  442.     do {
  443.         usleep(20000000);
  444.         snprintf(buffer, 1024, "PROCESS_SERVICE_CHECK_RESULT;nagios_proxy;%s;0;%0.2f svc_chk/sec %0.2fKB/sec\n", hostname, queue_additions/20.0f, queue_bytes/1024.0f/20.0f);
  445. #ifdef DEBUGA
  446.         fprintf(stderr, "%s", buffer);
  447. #endif
  448.         if (queue_additions == 0) {
  449.             print_timestamp(stderr);
  450.             fprintf(stderr, "No check results in 20 seconds, "
  451.                     "assuming error state, terminating\n");
  452.             exit(1);
  453.         }
  454.         queue_add(buffer);
  455.         queue_additions = 0;
  456.         queue_bytes = 0;
  457.     } while(1);
  458. }
  459.  
  460. static void print_timestamp(FILE *output)
  461. {
  462.     time_t now;
  463.     struct tm *ltm;
  464.     char timestr[1024], *timeasc;
  465.  
  466.     now = time(NULL);
  467.     ltm = localtime(&now);
  468.     timeasc = asctime(ltm);
  469.     strcpy(timestr, timeasc);
  470.     timestr[strlen(timestr)-1] = 0;
  471.     fprintf(output, "[%s] ", timestr);
  472. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement