metal/mtce/src/rmon/rmonApi/rmon_api.c

476 lines
16 KiB
C

/*
* Copyright (c) 2013, 2016 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
/**
* @file
* Wind River CGCS Platform Resource Monitor Client Notification API Library
* See rmon_api.h for API header.
*
**/
#include "rmon_api.h"
#include <sys/file.h>
/* Pass code */
#ifndef PASS
#define PASS (0)
#endif
/* Fail Code */
#ifndef FAIL
#define FAIL (1)
#endif
/* Retry Code */
#ifndef RETRY
#define RETRY (2)
#endif
/* maximum string and socket endpoint path length */
#define RMON_MAX_LEN (100)
/* initialization signature to gate functional
* api calls made prior to initialization */
#define INIT_SIG (0xffffdead)
/* rmon default messaging port */
#define RMONTXPORT 2300
/** Control Structure */
typedef struct
{
unsigned int init ; /**< Init signature */
int client_rx_sock ; /**< inet pulse request rx socket */
int client_rx_port ; /**< inet pulse request rx port number */
struct sockaddr_in client_rx_addr ; /**< inet pulse request rx attributes */
char client_rx_buf[RMON_MAX_LEN] ;
int rmon_tx_sock ; /**< inet pulse response tx socket */
int rmon_tx_port ; /**< inet pulse response tx port number */
struct sockaddr_in rmon_tx_addr ; /**< inet pulse response tx attributes */
char rmon_tx_buf[RMON_MAX_LEN] ;
int rmon_rx_sock ; /**< inet pulse response rx socket */
int rmon_rx_port ; /**< inet pulse response rx port number */
struct sockaddr_in rmon_rx_addr ; /**< inet pulse response rx attributes */
char rmon_rx_buf[RMON_MAX_LEN] ;
char name[RMON_MAX_LEN] ; /**< name of process using this instance */
bool debug_mode ; /**< debug mode if true */
int fit_code ; /**< fit code MAGIC, SEQ, PROCESS */
} resource_mon_socket_type ;
/* Instance Control Structure - Per Process Private Data */
static resource_mon_socket_type rmon ;
/* Mutex For sending client process information to rmon */
pthread_mutex_t client_mutex;
int remove_rmon_client( const char * process_name_ptr, int socket );
int add_rmon_client ( const char * process_name_ptr, int port , const char * registration, int rx_port);
int resource_monitor_initialize ( const char * process_name_ptr, int port , const char * registration);
int resource_monitor_deregister( const char * process_name_ptr, int socket );
int resource_monitor_get_sel_obj ( void );
int remove_rmon_client( const char * process_name_ptr, int socket );
void resource_monitor_finalize ();
int create_tx_socket();
/* Create and Setup Inet Transmit Socket
* return PASS (0) on success
* -# on kernel call error
* non-zero on internal error
*
**/
int create_tx_socket( int rx_port )
{
int val = 1 ;
int ok = 1 ;
rmon.rmon_tx_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if ( 0 >= rmon.rmon_tx_sock )
{
syslog ( LOG_ERR, "create_tx_socket failed to create 'tx' socket (%d:%m)", errno );
return (-errno);
}
if ( setsockopt ( rmon.rmon_tx_sock , SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1 )
{
syslog ( LOG_WARNING, "create_tx_socket failed to set 'tx' socket as reusable (%d:%m)", errno );
}
/* Setup with localhost ip */
memset(&rmon.rmon_tx_addr, 0, sizeof(struct sockaddr_in));
rmon.rmon_tx_addr.sin_family = AF_INET ;
rmon.rmon_tx_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
rmon.rmon_tx_addr.sin_port = htons(RMONTXPORT) ;
rmon.rmon_tx_port = RMONTXPORT ;
/* Set socket to be non-blocking. */
int rc = ioctl(rmon.rmon_tx_sock, FIONBIO, (char *)&ok);
if ( 0 > rc )
{
syslog ( LOG_WARNING, "create_tx_socket failed to set 'tx' socket as non-blocking (%d:%m)\n", errno );
}
/* if the sock is already open then close it first */
if ( rmon.rmon_rx_sock )
{
close (rmon.rmon_rx_sock);
}
rmon.rmon_rx_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if ( 0 >= rmon.rmon_rx_sock )
{
syslog ( LOG_WARNING, "create_rx_socket failed (%d:%m)\n", errno );
return (-errno);
}
if ( setsockopt ( rmon.rmon_rx_sock , SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1 )
{
syslog ( LOG_WARNING, "create_tx_socket failed to set 'rx' socket as reusable (%d:%m)", errno );
}
/* Setup with localhost ip */
memset(&rmon.rmon_rx_addr, 0, sizeof(struct sockaddr_in));
rmon.rmon_rx_addr.sin_family = AF_INET ;
rmon.rmon_rx_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
rmon.rmon_rx_addr.sin_port = htons(rx_port) ;
rmon.rmon_rx_port = rx_port ;
/* Set socket to be non-blocking. */
rc = ioctl(rmon.rmon_rx_sock, FIONBIO, (char *)&ok);
if ( 0 > rc )
{
syslog ( LOG_ERR, "create_tx_socket failed to set 'rx' socket as non-blocking (%d:%m)\n", errno );
return -errno;
}
/* bind socket to the receive addr */
if ( bind ( rmon.rmon_rx_sock, (const struct sockaddr *)&rmon.rmon_rx_addr, sizeof(struct sockaddr_in)) == -1 )
{
syslog ( LOG_ERR, "failed to bind rmon 'rx' socket with port %d (%d:%m)\n", rx_port, errno );
close (rmon.rmon_rx_sock);
rmon.rmon_rx_sock = 0 ;
return -errno;
}
return PASS;
}
/* open lo socket */
int add_rmon_client ( const char * process_name_ptr, int port , const char * registration, int rx_port)
{
struct stat p ;
int val = 1 ;
memset ( &rmon, 0, sizeof(rmon));
memset ( &p, 0 , sizeof(struct stat));
if ( registration == NULL )
{
syslog ( LOG_INFO, "resource_monitor_initialize called with null registration info");
return (0);
}
syslog ( LOG_INFO , "Add Client '%s' to rmon (port:%d)\n", registration, port );
sprintf ( rmon.name, "/var/run/%s.rmon", process_name_ptr );
stat ( rmon.name, &p ) ;
if ((p.st_ino != 0 ) && (p.st_dev != 0))
{
rmon.debug_mode = true ;
syslog ( LOG_INFO, "Enabling resource Monitor Debug Mode\n");
if ( p.st_size )
{
FILE * filename = fopen ( rmon.name, "rb" ) ;
if ( filename != NULL )
{
memset ( &rmon.name, 0, RMON_MAX_LEN);
if ( fgets ( rmon.name, 20, filename ) != NULL )
{
if ( !strncmp ( rmon.name, FIT_MAGIC_STRING, strlen (FIT_MAGIC_STRING)))
{
rmon.fit_code = FIT_MAGIC ;
syslog ( LOG_INFO, "Enabling FIT on 'magic calculation'\n");
}
else if ( !strncmp ( rmon.name, FIT_SEQUENCE_STRING, strlen(FIT_SEQUENCE_STRING)))
{
rmon.fit_code = FIT_SEQ ;
syslog ( LOG_INFO, "Enabling FIT on 'sequence number'\n");
}
else if ( !strncmp ( rmon.name, FIT_PROCESS_STRING, strlen(FIT_PROCESS_STRING)))
{
rmon.fit_code = FIT_PROCESS ;
syslog ( LOG_INFO, "Enabling FIT on 'process name'\n");
}
else
{
syslog ( LOG_INFO, "Unsupported FIT string (%s)\n", rmon.name );
}
}
fclose (filename);
}
else
{
syslog ( LOG_INFO, "Failed to open %s\n", rmon.name);
}
}
}
/* Init the control struct - includes all members */
memset ( rmon.name, 0, RMON_MAX_LEN);
if ( process_name_ptr )
{
memcpy ( rmon.name, process_name_ptr, strlen (process_name_ptr)) ;
}
else
{
syslog ( LOG_INFO, "resource_monitor_initialize called with null process name");
return (0);
}
/*******************************************************/
/* Create and Setup Inet Receive Socket */
/*******************************************************/
rmon.client_rx_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if ( 0 >= rmon.client_rx_sock )
{
syslog ( LOG_INFO, "add_rmon_client error:1");
return (0);
}
if ( setsockopt ( rmon.client_rx_sock , SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1 )
{
syslog ( LOG_INFO, "%s failed to set socket as re-useable (%d:%s)\n",
process_name_ptr, errno, strerror(errno));
}
/* Setup with localhost ip */
memset(&rmon.client_rx_addr, 0, sizeof(struct sockaddr_in));
rmon.client_rx_addr.sin_family = AF_INET ;
rmon.client_rx_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
rmon.client_rx_addr.sin_port = htons(port) ;
rmon.client_rx_port = port ;
/* bind socket to the receive addr */
if ( bind ( rmon.client_rx_sock, (const struct sockaddr *)&rmon.client_rx_addr, sizeof(struct sockaddr_in)) == -1 )
{
syslog ( LOG_ERR, "failed to bind to rx socket with port %d\n", port );
close (rmon.client_rx_sock);
rmon.client_rx_sock = 0 ;
return (0);
}
int rc = create_tx_socket ( rx_port );
if (rc != PASS )
{
syslog ( LOG_ERR, "add_rmon_client failed to create_tx_socket (rc:%d)", rc );
return (0);
}
if ((registration != NULL) && (rc == PASS))
{
int bytes = 0;
#ifdef WANT_CLIENT_REGISTER_SOCKET_SEND
socklen_t len = sizeof(struct sockaddr_in) ;
/* client registering, send rmon the resources registered for */
memset(rmon.rmon_tx_buf, 0, sizeof(rmon.rmon_tx_buf));
snprintf(rmon.rmon_tx_buf, sizeof(rmon.rmon_tx_buf), "%s %s %d", process_name_ptr, registration, port);
bytes = sendto ( rmon.rmon_tx_sock, &rmon.rmon_tx_buf, strlen(rmon.rmon_tx_buf), 0,
(struct sockaddr *) &rmon.rmon_tx_addr, sizeof(struct sockaddr_in));
fd_set readfds;
struct timeval waitd;
bytes = 0;
FD_ZERO(&readfds);
FD_SET(rmon.rmon_rx_sock, &readfds);
waitd.tv_sec = WAIT_DELAY;
waitd.tv_usec = 0;
/* This is used as a delay up to select_timeout */
select(FD_SETSIZE, &readfds, NULL, NULL, &waitd);
if (FD_ISSET(rmon.rmon_rx_sock, &readfds))
{
/* wait for the response from rmon to verify that the client is registered */
memset(rmon.rmon_rx_buf, 0, sizeof(rmon.rmon_rx_buf));
rmon.rmon_rx_buf[0] = 0;
bytes = recvfrom( rmon.rmon_rx_sock, rmon.rmon_rx_buf, RMON_MAX_LEN, 0, (struct sockaddr *)&rmon.rmon_rx_addr, &len );
}
#endif
if (bytes <= 0) {
/* no respone, write the client name and notification to a file for later use */
FILE * pFile;
memset(rmon.rmon_rx_buf, 0, sizeof(rmon.rmon_rx_buf));
snprintf(rmon.rmon_rx_buf, sizeof(rmon.rmon_rx_buf), "%s %s %d", process_name_ptr, registration, port);
pFile = fopen (RMON_API_REG_DIR , "a+");
if ( pFile )
{
// take out a writer lock on this file to
// ensure that no other entity is writing to it
// at this time
int lock = flock(fileno(pFile), LOCK_EX);
if (lock < 0) {
syslog (LOG_ERR, "Failed to get exclusive lock on"
" '%s' (errno: %d)", RMON_API_REG_DIR, errno);
} else {
fprintf(pFile, "%s\n", rmon.rmon_rx_buf);
// release write lock
flock(fileno(pFile), LOCK_UN);
}
fclose(pFile);
}
else
{
syslog ( LOG_ERR, "Failed to open '%s'\n", RMON_API_REG_DIR );
}
}
else
{
syslog ( LOG_ERR, "add_rmon_client send message succeeded");
}
/* Set init sig */
rmon.init = INIT_SIG ;
/* Return the socket descriptor */
return (rmon.client_rx_sock);
}
else
{
syslog ( LOG_ERR, "Failed register due to previous failure\n");
}
return (0);
}
int rmon_notification ( const char * notification_name )
{
int port = RMONTXPORT;
int rc;
/* send the message to check the dynamic file */
memset(rmon.rmon_tx_buf, 0, sizeof(rmon.rmon_tx_buf));
snprintf(rmon.rmon_tx_buf, sizeof(rmon.rmon_tx_buf), "%s %s %d", notification_name, RESOURCE_NOT, port);
rc = sendto ( rmon.rmon_tx_sock, &rmon.rmon_tx_buf, strlen(rmon.rmon_tx_buf), 0,
(struct sockaddr *) &rmon.rmon_tx_addr, sizeof(struct sockaddr_in));
return rc;
}
int resource_monitor_initialize ( const char * process_name_ptr, int port , const char * registration)
{
/* use a mutex to prevent multiple clients from registering at once */
int clt_rx_sock;
int rx_port = port - 1;
pthread_mutex_lock(&client_mutex);
clt_rx_sock = add_rmon_client(process_name_ptr, port , registration, rx_port );
pthread_mutex_unlock(&client_mutex);
return clt_rx_sock;
}
int resource_monitor_deregister( const char * process_name_ptr, int socket )
{
/* use a mutex to prevent multiple clients from de-registering at once */
int rc;
pthread_mutex_lock(&client_mutex);
rc = remove_rmon_client(process_name_ptr, socket);
pthread_mutex_unlock(&client_mutex);
return rc;
}
/* */
int resource_monitor_get_sel_obj ( void )
{
if (( rmon.init != INIT_SIG ) || ( rmon.client_rx_sock <= 0 ))
{
syslog (LOG_WARNING , "'%s' called with invalid init (sock:%d)\n",
__FUNCTION__, rmon.client_rx_sock);
}
return (rmon.client_rx_sock);
}
int remove_rmon_client( const char * process_name_ptr, int socket )
{
int rc;
int port = RMONTXPORT;
int bytes;
socklen_t len = sizeof(struct sockaddr_in);
/* client deregistering, send rmon the client process name */
memset(rmon.rmon_tx_buf, 0, sizeof(rmon.rmon_tx_buf));
snprintf(rmon.rmon_tx_buf, sizeof(rmon.rmon_tx_buf), "%s %s %d", process_name_ptr, CLR_CLIENT, port);
rc = sendto ( rmon.rmon_tx_sock, &rmon.rmon_tx_buf, strlen(rmon.rmon_tx_buf), 0,
(struct sockaddr *) &rmon.rmon_tx_addr, sizeof(struct sockaddr_in));
sleep(WAIT_DELAY);
/* wait for the response from rmon to verify that the client is de-registered */
memset(rmon.rmon_rx_buf, 0, sizeof(rmon.rmon_rx_buf));
rmon.rmon_rx_buf[0] = 0;
bytes = recvfrom( rmon.rmon_rx_sock, rmon.rmon_rx_buf, RMON_MAX_LEN, 0, (struct sockaddr *)&rmon.rmon_rx_addr, &len);
if ((bytes <= 0) || (rmon.rmon_rx_buf[0] == 0)) {
FILE * pFile;
memset(rmon.rmon_rx_buf, 0, sizeof(rmon.rmon_rx_buf));
snprintf(rmon.rmon_tx_buf, sizeof(rmon.rmon_tx_buf), "%s %s %d",
process_name_ptr, CLR_CLIENT, port);
pFile = fopen (RMON_API_DEREG_DIR , "a+");
if (pFile) {
// take out a writer lock on this file to
// ensure that no other entity is writing to it
// at this time
int lock = flock(fileno(pFile), LOCK_EX);
if (lock < 0) {
syslog (LOG_ERR, "Failed to get exclusive lock on"
" '%s' (errno: %d)", RMON_API_DEREG_DIR, errno);
} else{
fprintf(pFile, "%s\n", rmon.rmon_rx_buf);
// release the lock
flock(fileno(pFile), LOCK_UN);
}
fclose(pFile);
} else {
syslog (LOG_ERR, "Failed to open '%s'\n",
RMON_API_DEREG_DIR );
}
}
if ( socket )
{
/* close the client receive port */
close (socket);
}
rc = PASS ;
return rc;
}
/* close the rmon ports */
void resource_monitor_finalize ()
{
if ( rmon.rmon_tx_sock )
{
close (rmon.rmon_tx_sock);
}
if ( rmon.rmon_rx_sock )
{
close (rmon.rmon_rx_sock);
}
}