/* * cleopatre/application/managerd/src/managerd.c * * (C) Copyright 2009 SPiDCOM Technologies * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include #include #include #include #include #include #include "bridge.h" #include "mme_nl.h" #include "gpio_event.h" #include "managerd.h" /* Global variable indicating if a SIGHUP signal occurred, * has been caught in managerd signal handler, * and has now to be processed. */ volatile sig_atomic_t is_process_signal_needed; /* Global variable indicating if a SIGTERM signal occurred, should exit. */ volatile sig_atomic_t exit_requested; /** * Handle signal reception. * * \param signal_nb signal identifier */ void managerd_signal_handler (int signal_nb) { /* Check received signal. */ if (SIGHUP == signal_nb) { is_process_signal_needed = 1; } else if (SIGTERM == signal_nb) { exit_requested = 1; } } /** * This function is called after reception of a SIGHUP by managerd signal handler. * Check which information has changed in hpav.info file, * and depending on this information, call the appropriate processing function. * * \param ctx managerd context * \return -1 on error, 0 otherwise */ int managerd_process_signal (struct managerd_ctx *ctx) { /* hpav.info */ libspid_hpav_info_t hpav_info; memset (&hpav_info, 0, sizeof (libspid_hpav_info_t)); assert (NULL != ctx); /* read hpav.info file contents */ if (libspid_hpav_info_read_file (&hpav_info) != LIBSPID_SUCCESS) { syslog (LOG_WARNING, "libspid config read item failed"); return -1; } if (strcmp (hpav_info.status, ctx->hpav_info.status) || (hpav_info.is_sc != ctx->hpav_info.is_sc)) { /* attachment */ if (0 > led_attachment_event (ctx, hpav_info.status, hpav_info.is_sc)) { syslog (LOG_WARNING, "led attachment event failed"); return -1; } /* save values in managerd context */ strcpy (ctx->hpav_info.status, hpav_info.status); ctx->hpav_info.is_sc = hpav_info.is_sc; } if (strcmp (hpav_info.cco, ctx->hpav_info.cco)) { /* LED1 */ if (0 > led1_event (ctx, hpav_info.cco)) { syslog (LOG_WARNING, "led1 event failed"); return -1; } /* save value in managerd context */ strcpy (ctx->hpav_info.cco, hpav_info.cco); } if (hpav_info.is_backup_cco != ctx->hpav_info.is_backup_cco) { /* LED2 */ if (0 > led2_event (ctx, hpav_info.is_backup_cco)) { syslog (LOG_WARNING, "led2 event failed"); return -1; } /* save value in managerd context */ ctx->hpav_info.is_backup_cco = hpav_info.is_backup_cco; } return 0; } /** * Daemon core process. * Wait frame on BR and MME netlink, processing it before * sending it to BR or MME. * On each RX timeout, process other events. * * \param ctx managerd context. * \return error code. */ static int managerd_process(struct managerd_ctx *ctx) { uint8_t *buffer; int result = 0; int len; //Check arguments assert(ctx != NULL); //Allocate buffer for bridge part buffer = (uint8_t*)malloc(MAX_PKT_LEN); if(NULL == buffer) { syslog(LOG_WARNING, "cannot allocate memory (%s)", strerror(errno)); return -1; } while(!exit_requested) { fd_set readfds, exceptfds; struct timeval timeout; int result; //Configure timeout timeout.tv_sec = WAIT_TOUT; timeout.tv_usec = 0; FD_ZERO(&readfds); FD_ZERO (&exceptfds); FD_SET(ctx->sock_br, &readfds); FD_SET(ctx->sock_lo, &readfds); FD_SET (ctx->sock_mme, &readfds); FD_SET (ctx->gpio_fd, &exceptfds); //Select result = select (ctx->gpio_fd + 1, &readfds, NULL, &exceptfds, &timeout); /* Select error */ if (0 > result) { /* look for interrupt */ if (EINTR == errno) { /* reset errno */ errno = 0; /* process interrupt */ } else { syslog (LOG_WARNING, "select failed (%s)", strerror (errno)); return -1; } } else if (0 == result) { /* No reception coming */ } else if (FD_ISSET (ctx->sock_br, &readfds) || FD_ISSET (ctx->sock_lo, &readfds)) { //Receive a frame from bridge: process it len = bridge_receive(ctx, buffer, MAX_PKT_LEN, FD_ISSET (ctx->sock_lo, &readfds) /* check for local if */); if(0 >= len) { result = -1; break; } //Processing this reception if(TO_SEND == bridge_processing(ctx, buffer, &len, MAX_PKT_LEN)) { //Send the process result to bridge interface len = bridge_send(ctx, buffer, len); if(0 > len) { result = -1; break; } } } else if FD_ISSET (ctx->sock_mme, &readfds) { //Receive a frame from MME if len = mme_nl_receive(ctx, buffer, MAX_PKT_LEN); if(0 >= len) { result = -1; break; } //relay it to the bridge len = bridge_send(ctx, buffer, len); if(0 > len) { result = -1; break; } } else if (FD_ISSET (ctx->gpio_fd, &exceptfds)) { /* Manage simple connect */ if (0 > simple_connect_event (ctx)) break; else continue; } if (is_process_signal_needed) { is_process_signal_needed = 0; /* now handle all info file changes (from plcd) */ managerd_process_signal (ctx); } } //Freeing buffer free(buffer); return result; } /** * Initialize managerd and prepare context. * * \param ctx managerd context. * \return error code. */ static int managerd_init(struct managerd_ctx *ctx) { //Check arguments assert(ctx != NULL); //Set context memset(ctx, '\0', sizeof(struct managerd_ctx)); //Initialize bridge part if(0 > bridge_init(ctx)) return -1; //Initialize mme part if (0 > mme_nl_init (ctx)) { bridge_uninit (ctx); return -1; } //Initialize simple connect part (open "/dev/gpio") if (0 > simple_connect_init (ctx)) { bridge_uninit (ctx); mme_nl_uninit (ctx); return -1; } /* Initialize led part (need "/dev/gpio") */ if (0 > led_init (ctx)) { bridge_uninit (ctx); mme_nl_uninit (ctx); simple_connect_uninit (ctx); return -1; } /* Set default values of hpav.info file into managerd context */ strcpy (ctx->hpav_info.status, LIBSPID_HPAV_INFO_VALUE_STATUS_UNASSOCIATED); strcpy (ctx->hpav_info.cco, LIBSPID_HPAV_INFO_VALUE_CCO_STATION); ctx->hpav_info.is_backup_cco = LIBSPID_FALSE; ctx->hpav_info.is_sc = LIBSPID_FALSE; ctx->hpav_info.is_sc_button = LIBSPID_FALSE; /* Initialize to 1 to set LED-s status * according to current hpav.info contents. */ is_process_signal_needed = 1; /* Register to hpav.info file update */ if (LIBSPID_SUCCESS != libspid_system_file_update_register (getpid(), LIBSPID_HPAV_INFO_PATH, managerd_signal_handler)) { syslog (LOG_WARNING, "libspid system file update register failed"); bridge_uninit (ctx); mme_nl_uninit (ctx); led_uninit (ctx); simple_connect_uninit (ctx); return -1; } /* Catch SIGTERM. */ signal (SIGTERM, managerd_signal_handler); return 0; } /** * Uninitialize manager daemon. * * \param ctx managerd context. */ static void managerd_uninit(struct managerd_ctx *ctx) { //Check arguments assert(ctx != NULL); //Uninitialize bridge part bridge_uninit(ctx); //Uninitialize mme part mme_nl_uninit(ctx); /* Uninitialize led part (need "/dev/gpio") */ led_uninit (ctx); //Uninitialize simple connect part (close "/dev/gpio") simple_connect_uninit(ctx); /* Unregister to file update. */ libspid_system_file_update_unregister (getpid (), LIBSPID_HPAV_INFO_PATH); } /** * Main function * * \param argc number of arguments. * \param argv arguments pointer. * \return error code. */ int main(int argc, char **argv) { struct managerd_ctx ctx; int result; //Open syslog file openlog("managerd", LOG_PID, LOG_DAEMON); //Initialize manager daemon if(0 != managerd_init(&ctx)) { closelog(); return -1; } syslog (LOG_NOTICE, "Manager Daemon Running"); //Start manager daemon core result = managerd_process(&ctx); syslog (LOG_NOTICE, "Manager Daemon exiting"); //Uninitialize manager daemon managerd_uninit(&ctx); //Open syslog file closelog(); return result; }