Advertisement
Guest User

s0vz.c

a guest
May 6th, 2015
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.90 KB | None | 0 0
  1. /**************************************************************************
  2.  
  3. S0/Impulse to Volkszaehler 'RaspberryPI deamon'.
  4.  
  5. https://github.com/w3llschmidt/s0vz.git
  6.  
  7. Henrik Wellschmidt  <[email protected]>
  8.  
  9. **************************************************************************/
  10.  
  11. #define DAEMON_NAME "s0vz"
  12. #define DAEMON_VERSION "1.4"
  13. #define DAEMON_BUILD "4"
  14.  
  15. /**************************************************************************
  16.  
  17. This program is free software: you can redistribute it and/or modify
  18. it under the terms of the GNU General Public License as published by
  19. the Free Software Foundation, either version 3 of the License, or
  20. (at your option) any later version.
  21.  
  22. This program is distributed in the hope that it will be useful,
  23. but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25. GNU General Public License for more details.
  26.  
  27. You should have received a copy of the GNU General Public License
  28. along with this program.  If not, see <http://www.gnu.org/licenses/>.
  29.  
  30. **************************************************************************/
  31.  
  32. #include <stdio.h>              /* standard library functions for file input and output */
  33. #include <stdlib.h>             /* standard library for the C programming language, */
  34. #include <string.h>             /* functions implementing operations on strings  */
  35. #include <unistd.h>             /* provides access to the POSIX operating system API */
  36. #include <sys/stat.h>           /* declares the stat() functions; umask */
  37. #include <fcntl.h>              /* file descriptors */
  38. #include <syslog.h>             /* send messages to the system logger */
  39. #include <errno.h>              /* macros to report error conditions through error codes */
  40. #include <signal.h>             /* signal processing */
  41. #include <stddef.h>             /* defines the macros NULL and offsetof as well as the types ptrdiff_t, wchar_t, and size_t */
  42.  
  43. #include <libconfig.h>          /* reading, manipulating, and writing structured configuration files */
  44. #include <curl/curl.h>          /* multiprotocol file transfer library */
  45. #include <poll.h>           /* wait for events on file descriptors */
  46.  
  47. #include <sys/ioctl.h>      /* */
  48.  
  49. #define BUF_LEN 64
  50.  
  51. void daemonShutdown();
  52. void signal_handler(int sig);
  53. void daemonize(char *rundir, char *pidfile);
  54.  
  55. int pidFilehandle, vzport, i, len, running_handles, rc;
  56.  
  57. const char *vzserver, *vzpath, *vzuuid[64];
  58.  
  59. char gpio_pin_id[] = { 17, 18 }, url[128];
  60.  
  61. int inputs = sizeof(gpio_pin_id)/sizeof(gpio_pin_id[0]);
  62.  
  63. struct timeval tv;
  64.  
  65. CURL *easyhandle[sizeof(gpio_pin_id)/sizeof(gpio_pin_id[0])];
  66. CURLM *multihandle;
  67. CURLMcode multihandle_res;
  68.  
  69. static char errorBuffer[CURL_ERROR_SIZE+1];
  70.  
  71. void signal_handler(int sig) {
  72.  
  73.     switch(sig)
  74.     {
  75.         case SIGHUP:
  76.         syslog(LOG_WARNING, "Received SIGHUP signal.");
  77.         break;
  78.         case SIGINT:
  79.         case SIGTERM:
  80.         syslog(LOG_INFO, "Daemon exiting");
  81.         daemonShutdown();
  82.         exit(EXIT_SUCCESS);
  83.         break;
  84.         default:
  85.         syslog(LOG_WARNING, "Unhandled signal %s", strsignal(sig));
  86.         break;
  87.     }
  88. }
  89.  
  90. void daemonShutdown() {
  91.         close(pidFilehandle);
  92.         remove("/tmp/s0vz.pid");
  93. }
  94.  
  95. void daemonize(char *rundir, char *pidfile) {
  96.     int pid, sid, i;
  97.     char str[10];
  98.     struct sigaction newSigAction;
  99.     sigset_t newSigSet;
  100.  
  101.     if (getppid() == 1)
  102.     {
  103.         return;
  104.     }
  105.  
  106.     sigemptyset(&newSigSet);
  107.     sigaddset(&newSigSet, SIGCHLD);
  108.     sigaddset(&newSigSet, SIGTSTP);
  109.     sigaddset(&newSigSet, SIGTTOU);
  110.     sigaddset(&newSigSet, SIGTTIN);
  111.     sigprocmask(SIG_BLOCK, &newSigSet, NULL);
  112.  
  113.     newSigAction.sa_handler = signal_handler;
  114.     sigemptyset(&newSigAction.sa_mask);
  115.     newSigAction.sa_flags = 0;
  116.  
  117.     sigaction(SIGHUP, &newSigAction, NULL);
  118.     sigaction(SIGTERM, &newSigAction, NULL);
  119.     sigaction(SIGINT, &newSigAction, NULL);
  120.  
  121.     pid = fork();
  122.  
  123.     if (pid < 0)
  124.     {
  125.         exit(EXIT_FAILURE);
  126.     }
  127.  
  128.     if (pid > 0)
  129.     {
  130.         printf("Child process created: %d\n", pid);
  131.         exit(EXIT_SUCCESS);
  132.     }
  133.    
  134.     umask(027);
  135.  
  136.     sid = setsid();
  137.     if (sid < 0)
  138.     {
  139.         exit(EXIT_FAILURE);
  140.     }
  141.  
  142.     for (i = getdtablesize(); i >= 0; --i)
  143.     {
  144.         close(i);
  145.     }
  146.  
  147.     close(STDIN_FILENO);
  148.     close(STDOUT_FILENO);
  149.     close(STDERR_FILENO);
  150.  
  151.     chdir(rundir);
  152.  
  153.     pidFilehandle = open(pidfile, O_RDWR|O_CREAT, 0600);
  154.  
  155.     if (pidFilehandle == -1 )
  156.     {
  157.         syslog(LOG_INFO, "Could not open PID lock file %s, exiting", pidfile);
  158.         exit(EXIT_FAILURE);
  159.     }
  160.  
  161.     if (lockf(pidFilehandle,F_TLOCK,0) == -1)
  162.     {
  163.         syslog(LOG_INFO, "Could not lock PID lock file %s, exiting", pidfile);
  164.         exit(EXIT_FAILURE);
  165.     }
  166.  
  167.     sprintf(str,"%d\n",getpid());
  168.  
  169.     write(pidFilehandle, str, strlen(str));
  170. }
  171.  
  172. void cfile() {
  173.  
  174.     config_t cfg;
  175.  
  176.     //config_setting_t *setting;
  177.  
  178.     config_init(&cfg);
  179.  
  180.     int chdir(const char *path);
  181.  
  182.     chdir ("/etc");
  183.  
  184.     if(!config_read_file(&cfg, DAEMON_NAME".cfg"))
  185.     {
  186.         syslog(LOG_INFO, "Config error > /etc/%s - %s\n", config_error_file(&cfg),config_error_text(&cfg));
  187.         config_destroy(&cfg);
  188.         daemonShutdown();
  189.         exit(EXIT_FAILURE);
  190.     }
  191.  
  192.     if (!config_lookup_string(&cfg, "vzserver", &vzserver))
  193.     {
  194.         syslog(LOG_INFO, "Missing 'VzServer' setting in configuration file.");
  195.         config_destroy(&cfg);
  196.         daemonShutdown();
  197.         exit(EXIT_FAILURE);
  198.     }
  199.     else
  200.     syslog(LOG_INFO, "VzServer:%s", vzserver);
  201.  
  202.     if (!config_lookup_int(&cfg, "vzport", &vzport))
  203.     {
  204.         syslog(LOG_INFO, "Missing 'VzPort' setting in configuration file.");
  205.         config_destroy(&cfg);
  206.         daemonShutdown();
  207.         exit(EXIT_FAILURE);
  208.     }
  209.     else
  210.     syslog(LOG_INFO, "VzPort:%d", vzport);
  211.  
  212.  
  213.     if (!config_lookup_string(&cfg, "vzpath", &vzpath))
  214.     {
  215.         syslog(LOG_INFO, "Missing 'VzPath' setting in configuration file.");
  216.         config_destroy(&cfg);
  217.         daemonShutdown();
  218.         exit(EXIT_FAILURE);
  219.     }
  220.     else
  221.     syslog(LOG_INFO, "VzPath:%s", vzpath);
  222.  
  223.     for (i=0; i<inputs; i++)
  224.     {
  225.         char gpio[6];
  226.         sprintf ( gpio, "GPIO%01d", i );
  227.         if ( config_lookup_string( &cfg, gpio, &vzuuid[i]) == CONFIG_TRUE )
  228.         syslog ( LOG_INFO, "%s = %s", gpio, vzuuid[i] );
  229.     }
  230.  
  231. }
  232.  
  233. unsigned long long unixtime() {
  234.  
  235.     gettimeofday(&tv,NULL);
  236.     unsigned long long ms_timestamp = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;
  237.  
  238. return ms_timestamp;
  239. }
  240.  
  241. void update_curl_handle(const char *vzuuid) {
  242.  
  243.         curl_multi_remove_handle(multihandle, easyhandle[i]);
  244.        
  245.         syslog(LOG_INFO, "update_curl_handle URL: http://%s:%d/%s/data/%s.json?ts=%llu", vzserver, vzport, vzpath, vzuuid, unixtime());
  246.  
  247.         sprintf(url, "http://%s:%d/%s/data/%s.json?ts=%llu", vzserver, vzport, vzpath, vzuuid, unixtime());
  248.        
  249.         curl_easy_setopt(easyhandle[i], CURLOPT_URL, url);
  250.        
  251.         curl_multi_add_handle(multihandle, easyhandle[i]);
  252.                
  253. }
  254.  
  255. int main(void) {
  256.  
  257.     freopen( "/dev/null", "r", stdin);
  258.     freopen( "/dev/null", "w", stdout);
  259.     freopen( "/dev/null", "w", stderr);
  260.  
  261.     FILE* devnull = NULL;      
  262.     devnull = fopen("/dev/null", "w+");
  263.        
  264.     setlogmask(LOG_UPTO(LOG_INFO));
  265.     openlog(DAEMON_NAME, LOG_CONS | LOG_PERROR, LOG_USER);
  266.  
  267.     syslog ( LOG_INFO, "S0/Impulse to Volkszaehler RaspberryPI deamon %s.%s", DAEMON_VERSION, DAEMON_BUILD );
  268.    
  269.     cfile();
  270.    
  271.     char pid_file[16];
  272.     sprintf ( pid_file, "/tmp/%s.pid", DAEMON_NAME );
  273.     daemonize( "/tmp/", pid_file );
  274.    
  275.         char buffer[BUF_LEN];
  276.         struct pollfd fds[inputs];
  277.        
  278.         curl_global_init(CURL_GLOBAL_ALL);
  279.         multihandle = curl_multi_init();
  280.            
  281.         for (i=0; i<inputs; i++) {
  282.        
  283.             snprintf ( buffer, BUF_LEN, "/sys/class/gpio/gpio%d/value", gpio_pin_id[i] );
  284.  
  285.             if((fds[i].fd = open(buffer, O_RDONLY|O_NONBLOCK)) == 0) {
  286.            
  287.                 syslog(LOG_INFO,"Error:%s (%m)", buffer);
  288.                 exit(1);
  289.                
  290.             }
  291.        
  292.             fds[i].events = POLLPRI;
  293.             fds[i].revents = 0;
  294.                
  295.             easyhandle[i] = curl_easy_init();
  296.            
  297.             curl_easy_setopt(easyhandle[i], CURLOPT_URL, url);
  298.             curl_easy_setopt(easyhandle[i], CURLOPT_POSTFIELDS, "");
  299.             curl_easy_setopt(easyhandle[i], CURLOPT_USERAGENT, DAEMON_NAME " " DAEMON_VERSION );
  300.             curl_easy_setopt(easyhandle[i], CURLOPT_WRITEDATA, devnull);
  301.             curl_easy_setopt(easyhandle[i], CURLOPT_ERRORBUFFER, errorBuffer);
  302.            
  303.             curl_multi_add_handle(multihandle, easyhandle[i]);
  304.                                        
  305.         }
  306.                                        
  307.             for ( ;; ) {
  308.            
  309.                 if((multihandle_res = curl_multi_perform(multihandle, &running_handles)) != CURLM_OK) {
  310.                     syslog(LOG_INFO, "HTTP_POST(): %s", curl_multi_strerror(multihandle_res) );
  311.                 }
  312.                
  313.             /*  if (i++ % log_poll_seconds == 0) {
  314.                     syslog(LOG_INFO, "Before poll()");
  315.                 }*/
  316.  
  317.                 int ret = poll(fds, inputs, 1000);
  318.                        
  319.                 if(ret>0) {
  320.                     syslog(LOG_INFO, "Got something, ret > 0");
  321.                     for (i=0; i<inputs; i++) {
  322.                         if (fds[i].revents & POLLPRI) {
  323.                             syslog(LOG_INFO, "Before read");
  324.                             len = read(fds[i].fd, buffer, BUF_LEN);
  325.                             syslog(LOG_INFO, "after read");
  326.                             syslog(LOG_INFO, "Beforde update curl handle");
  327.                             update_curl_handle(vzuuid[i]);
  328.                             syslog(LOG_INFO, "After update curl handle");
  329.                         }
  330.                     }
  331.                 } else {
  332.                     syslog(LOG_INFO, "Got something, ret <= 0");
  333.                 }
  334.             }
  335.    
  336.         curl_global_cleanup();
  337.    
  338. return 0;
  339. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement