metal/mtce/src/mtclog/mtclog.cpp

339 lines
9.5 KiB
C++

/*
* Copyright (c) 2015-2016 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
/**
* @file
* Wind River CGCS Platform maintenance Log daemon
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netdb.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <list>
using namespace std;
#include "daemon_ini.h"
#include "daemon_common.h"
#include "daemon_option.h"
#include "nodeBase.h" /* for ... service module header */
#include "nodeTimers.h" /* Timer Service */
#include "nodeUtil.h" /* Common Utilities */
#include "nodeMacro.h" /* for ... CREATE_NONBLOCK_INET_UDP_RX_SOCKET */
// #include "mtcNodeMsg.h" /* Common Messaging */
string my_hostname = "" ;
string my_local_ip = "" ;
string my_float_ip = "" ;
static daemon_config_type _config ;
daemon_config_type * daemon_get_cfg_ptr () { return &_config ; }
static msgSock_type log_sock ;
/* Cleanup exit handler */
void daemon_exit ( void )
{
fflush (stdout);
fflush (stderr);
if ( log_sock.sock > 0 )
{
close(log_sock.sock);
log_sock.sock = 0 ;
}
exit (0);
}
/*******************************************************************
* Module Utilities *
******************************************************************/
/* SIGCHLD handler support - for waitpid */
void daemon_sigchld_hdlr ( void )
{
dlog("Received SIGCHLD ...\n");
}
/*****************************************************************************
*
* Name : _config_handler
*
* Purpose : Read specified config options
*
*****************************************************************************/
static int _config_handler ( void * user,
const char * section,
const char * name,
const char * value)
{
daemon_config_type* config_ptr = (daemon_config_type*)user;
if (MATCH("client", "daemon_log_port"))
{
config_ptr->daemon_log_port = atoi(value);
// ilog ("Log port = %d\n", atoi(value));
}
return (PASS);
}
/*****************************************************************************
*
* Name : daemon_configure
*
* Purpose : Run the config handler against a specified config file.
*
*****************************************************************************/
int daemon_configure ( void )
{
int rc = PASS ;
if (ini_parse( MTCE_CONF_FILE, _config_handler, &_config) < 0)
{
elog("Can't load '%s'\n", MTCE_CONF_FILE );
}
get_debug_options ( MTCE_CONF_FILE, &_config );
/* This ensures any link aggregation interface overrides the physical */
_config.mgmnt_iface = daemon_get_iface_master ( _config.mgmnt_iface );
ilog("Mgmnt Iface : %s\n", _config.mgmnt_iface );
bool waiting_msg = false ;
for ( ;; )
{
get_ip_addresses ( my_hostname, my_local_ip , my_float_ip );
if ( my_float_ip.empty() || my_local_ip.empty() )
{
if ( waiting_msg == false )
{
ilog ("Waiting on ip address config ...\n");
waiting_msg = true ;
/* Flush the init data */
fflush (stdout);
fflush (stderr);
}
mtcWait_secs (3);
}
else
{
break ;
}
}
ilog("Logger Port : %d\n", _config.daemon_log_port );
return (rc);
}
/****************************/
/* Initialization Utilities */
/****************************/
/* Setup the daemon messaging interfaces/sockets */
int socket_init ( void )
{
int rc = FAIL ;
int port = _config.daemon_log_port ;
CREATE_NONBLOCK_INET_UDP_RX_SOCKET ( LOOPBACK_IP,
port,
log_sock.sock,
log_sock.addr,
log_sock.port,
log_sock.len,
"daemon log receiver",
rc );
if ( rc )
{
printf ("Failed to setup the daemon log reciver port %d\n", _config.daemon_log_port );
}
return (rc);
}
/* The main heartbeat service loop */
int daemon_init ( string iface, string nodetype )
{
int rc = PASS ;
/* Not used by this daemon */
UNUSED(nodetype);
/* init the control struct */
my_hostname = "" ;
my_local_ip = "" ;
my_float_ip = "" ;
/* Assign interface to config */
_config.mgmnt_iface = (char*)iface.data() ;
if ( daemon_files_init ( ) != PASS )
{
elog ("Pid, log or other files could not be opened\n");
return ( FAIL_FILES_INIT ) ;
}
/* Bind signal handlers */
if ( daemon_signal_init () != PASS )
{
elog ("daemon_signal_init failed\n");
return ( FAIL_SIGNAL_INIT ) ;
}
/************************************************************************
* There is no point continuing with init ; i.e. running daemon_configure,
* initializing sockets and trying to query for an ip address until the
* daemon's configuration requirements are met. Here we wait for those
* flag files to be present before continuing.
************************************************************************
* Wait for /etc/platform/.initial_config_complete & /var/run/.goenabled */
daemon_wait_for_file ( CONFIG_COMPLETE_FILE , 0);
daemon_wait_for_file ( GOENABLED_MAIN_READY , 0);
/* Configure the daemon */
if ( (rc = daemon_configure ( )) != PASS )
{
elog ("Daemon service configuration failed (rc:%i)\n", rc );
rc = FAIL_DAEMON_CONFIG ;
}
/* Setup the messaging sockets */
else if ( (rc = socket_init ( )) != PASS )
{
elog ("socket initialization failed (rc:%d)\n", rc );
rc = FAIL_SOCKET_INIT ;
}
return (rc);
}
/* ****************************************************
* Start the service
* ****************************************************/
void daemon_service_run ( void )
{
int rc = PASS ;
int count = 0 ;
/* For select dispatch */
struct timeval waitd ;
fd_set readfds;
/* Wait for config complete indicated by presence
* of /etc/platform/.initial_config_complete */
struct stat p ;
memset ( &p, 0 , sizeof(struct stat));
do
{
stat (CONFIG_COMPLETE_FILE, &p);
mtcWait_secs (2);
wlog_throttled ( count, 60, "Waiting for %s\n", CONFIG_COMPLETE_FILE);
/* The CONFIG_COMPLETE file may be empty so don't look at size,
* look at the node and dev ids as non-zero instead */
} while ((p.st_ino == 0 ) || (p.st_dev == 0)) ;
/* Run daemon main loop */
for ( ; ; )
{
if ( log_sock.sock <= 0 )
{
daemon_exit ();
}
/* Initialize the timeval struct to wait for 1 mSec */
waitd.tv_sec = 0;
waitd.tv_usec = (SOCKET_WAIT*5);
FD_ZERO(&readfds);
FD_SET(log_sock.sock, &readfds);
/* Call select() and wait only up to SOCKET_WAIT */
rc = select( log_sock.sock+1, &readfds, NULL, NULL, &waitd);
/* If the select time out expired then */
if (( rc < 0 ) || ( rc == 0 ))
{
/* Check to see if the select call failed. */
/* ... but filter Interrupt signal */
if (( rc < 0 ) && ( errno != EINTR ))
{
elog ("Select Failed (rc:%d) %s\n", errno, strerror(errno));
}
}
else
{
if (FD_ISSET(log_sock.sock, &readfds))
{
int bytes ;
log_message_type log ;
unsigned int len = sizeof(log_sock.addr);
/* Look for maintenance command messages */
memset (&log, 0, sizeof(log_message_type));
bytes = recvfrom ( log_sock.sock,
(char*)&log, sizeof(log_message_type), 0,
(struct sockaddr *) &log_sock.addr, &len );
if ( bytes > 0 )
{
if ( strnlen ( &log.hostname[0], MAX_HOST_NAME_SIZE ))
{
if ( strnlen ( &log.filename[0], MAX_FILENAME_LEN ))
{
if ( strnlen ( &log.logbuffer[0], MAX_LOG_MSG ))
{
char temp_buf [20] ;
strncpy ( temp_buf, &log.logbuffer[0], 19 );
temp_buf[19] = '\0' ;
dlog ("%s %s [%s]\n", &log.hostname[0], &log.filename[0], &temp_buf[0] );
daemon_log ( &log.filename[0], &log.logbuffer[0] );
}
}
}
}
}
}
daemon_signal_hdlr ();
}
daemon_exit ();
}
/* Push daemon state to log file */
void daemon_dump_info ( void )
{
daemon_dump_membuf_banner ();
daemon_dump_membuf();
}
const char MY_DATA [100] = { "eieio\n" } ;
const char * daemon_stream_info ( void )
{
return (&MY_DATA[0]);
}
/** Teat Head Entry */
int daemon_run_testhead ( void )
{
ilog ("Empty test head.\n");
return (PASS);
}