fault/fm-common/sources/fmAPI.cpp
Erich Cordoba f9ba635bfd Fix indentation and style issues in fmAPI
Several indentation issues were solved, also some style was applied
to improve code's readability.

No funcionality changes were done.

Story: 2006425
Task: 36322

Change-Id: Ie3339ed10254a053a2e26397337c45dfa2d552bd
Signed-off-by: Erich Cordoba <erich.cordoba.malibran@intel.com>
2019-08-22 10:53:15 -05:00

536 lines
14 KiB
C++

//
// Copyright (c) 2017 Wind River Systems, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <list>
#include <new>
#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#include "fmAPI.h"
#include "fmMsg.h"
#include "fmLog.h"
#include "fmSocket.h"
#include "fmMutex.h"
#include "fmThread.h"
#include "fmAlarmUtils.h"
#define FM_MGR_HOST_NAME "controller"
#define MAX_PENDING_REQUEST 1000
#define HANDLE_SERVER_RC(hdr) \
if ((hdr)->msg_rc!=FM_ERR_OK) return (EFmErrorT) (hdr)->msg_rc
#define CHECK_RESPONSE(hdr,neededstruct) \
if (!fm_valid_srv_msg(hdr,sizeof(neededstruct))) \
return FM_ERR_COMMUNICATIONS
#define CHECK_LIST_FULL(l) \
if (l.size() == MAX_PENDING_REQUEST) \
return FM_ERR_NOT_ENOUGH_SPACE
#define CHECK_LIST_NOT_EMPTY(l) \
if (l.size() != 0) \
return FM_ERR_REQUEST_PENDING
static CFmSocket m_client;
static bool m_connected = false;
static bool m_thread = false;
typedef std::list<fm_buff_t> FmRequestListT;
static FmRequestListT & GetListOfFmRequests() {
static FmRequestListT reqs;
return reqs;
}
static CFmMutex & getListMutex() {
static CFmMutex *m = new CFmMutex;
return *m;
}
static CFmMutex & getThreadMutex() {
static CFmMutex *m = new CFmMutex;
return *m;
}
CFmMutex & getAPIMutex() {
static pthread_mutex_t ml = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
static CFmMutex *m = NULL;
if (m == NULL) {
pthread_mutex_lock(&ml);
m = new CFmMutex;
pthread_mutex_unlock(&ml);
}
return *m;
}
static void enqueue(fm_buff_t &req) {
CFmMutexGuard m(getListMutex());
GetListOfFmRequests().push_back(req);
}
static bool dequeue(fm_buff_t &req) {
CFmMutexGuard m(getListMutex());
if (GetListOfFmRequests().size() == 0) {
return false;
}
FmRequestListT::iterator it = GetListOfFmRequests().begin();
req.clear();
req = (*it);
GetListOfFmRequests().pop_front();
return true;
}
static bool fm_lib_reconnect() {
char addr[INET6_ADDRSTRLEN];
while (!m_connected) {
struct addrinfo hints;
struct addrinfo *result = NULL, *rp;
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
hints.ai_flags = 0; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
int rc = getaddrinfo(FM_MGR_HOST_NAME, NULL,
&hints,
&result);
if (rc != 0) {
FM_ERROR_LOG("controller lookup failed... errno:%d", errno);
break;
} else {
for (rp = result; rp != NULL; rp = rp->ai_next) {
if (rp->ai_family == AF_INET || rp->ai_family==AF_INET6) {
if(rp->ai_family == AF_INET) {
inet_ntop(AF_INET, &(((sockaddr_in*)rp->ai_addr)->sin_addr), addr, sizeof(addr));
} else if (rp->ai_family == AF_INET6) {
inet_ntop(AF_INET6, &(((sockaddr_in6*)rp->ai_addr)->sin6_addr), addr, sizeof(addr));
}
m_connected = m_client.connect(addr, 8001, rp->ai_family);
if (m_connected == true) {
FM_INFO_LOG("Connected to FM Manager.");
break;
} else {
FM_WARNING_LOG("Failed to connect to FM Manager.");
}
}
}
freeaddrinfo(result);
}
break;
}
return (m_connected);
}
EFmErrorT fm_msg_utils_prep_requet_msg(fm_buff_t &buff,
EFmMsgActionsT act,
const void * data,
uint32_t len) {
try {
buff.resize(sizeof(SFmMsgHdrT) + len);
} catch (...) {
FM_ERROR_LOG("Buff resize failed: errno:%d",errno);
return FM_ERR_NOMEM;
}
SFmMsgHdrT *hdr = ptr_to_hdr(buff);
hdr->action = act;
hdr->msg_size = len;
hdr->version = EFmMsgV1;
hdr->msg_rc = 0;
memcpy(ptr_to_data(buff), data, len);
return FM_ERR_OK;
}
static void fmApiJobHandlerThread(void *context) {
while (true) {
fm_buff_t buff;
buff.clear();
while (dequeue(buff)) {
while (true) {
while (!fm_lib_reconnect()) {
fmThreadSleep(200);
}
fm_log_request(buff);
// protect from other sync APIs to access the same socket
CFmMutexGuard m(getAPIMutex());
if(m_client.write_packet(buff)) {
fm_buff_t in_buff;
in_buff.clear();
if(!m_client.read_packet(in_buff)) {
// retry after read failure
fm_log_response(buff, in_buff, true);
m_connected = false;
continue;
} else {
fm_log_response(buff, in_buff);
break;
}
} else {
// retry after write failure
fm_log_request(buff, true);
m_connected = false;
continue;
}
}
}
fmThreadSleep(50);
}
}
static bool fm_lib_thread() {
CFmMutexGuard m(getThreadMutex());
if (!m_thread) {
FM_INFO_LOG("Creating thread");
if (!fmCreateThread(fmApiJobHandlerThread, NULL)) {
FM_ERROR_LOG("Fail to create API job thread");
} else {
m_thread = true;
}
}
return m_thread;
}
static EFmErrorT fm_check_thread_pending_request() {
CFmMutexGuard m(getThreadMutex());
if (m_thread) {
CHECK_LIST_NOT_EMPTY(GetListOfFmRequests());
}
return FM_ERR_OK;
}
extern "C" {
EFmErrorT fm_init_lib() {
signal(SIGINT,SIG_IGN);
CFmMutexGuard m(getAPIMutex());
if (!fm_lib_reconnect()) {
FM_ERROR_LOG("Socket connection failed\n");
return FM_ERR_NOCONNECT;
}
return FM_ERR_OK;
}
EFmErrorT fm_set_fault(const SFmAlarmDataT *alarm,
fm_uuid_t *uuid) {
CFmMutexGuard m(getAPIMutex());
if (!fm_lib_reconnect()) return FM_ERR_NOCONNECT;
fm_buff_t buff;
buff.clear();
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmCreateFault,
alarm,sizeof(*alarm));
if (erc!=FM_ERR_OK) return erc;
if (m_client.write_packet(buff)) {
if (!m_client.read_packet(buff)) {
m_connected = false;
return FM_ERR_NOCONNECT;
}
HANDLE_SERVER_RC(ptr_to_hdr(buff));
CHECK_RESPONSE(ptr_to_hdr(buff),fm_uuid_t);
if (uuid != NULL)
memcpy(*uuid,ptr_to_data(buff),sizeof(*uuid)-1);
} else {
m_connected = false;
return FM_ERR_NOCONNECT;
}
return FM_ERR_OK;
}
EFmErrorT fm_clear_fault(AlarmFilter *filter) {
CFmMutexGuard m(getAPIMutex());
if (!fm_lib_reconnect()) return FM_ERR_NOCONNECT;
fm_buff_t buff;
buff.clear();
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmDeleteFault,
filter, sizeof(*filter));
if (erc!=FM_ERR_OK) return erc;
if (m_client.write_packet(buff)) {
if (!m_client.read_packet(buff)) {
m_connected = false;
return FM_ERR_NOCONNECT;
}
HANDLE_SERVER_RC(ptr_to_hdr(buff));
} else {
m_connected = false;
return FM_ERR_NOCONNECT;
}
return FM_ERR_OK;
}
EFmErrorT fm_clear_all(fm_ent_inst_t *inst_id) {
CFmMutexGuard m(getAPIMutex());
if (!fm_lib_reconnect()) return FM_ERR_NOCONNECT;
fm_buff_t buff;
buff.clear();
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmDeleteFaults,
(*inst_id), sizeof(*inst_id));
if (erc!=FM_ERR_OK) return erc;
if (m_client.write_packet(buff)) {
if (!m_client.read_packet(buff)) {
m_connected = false;
FM_ERROR_LOG("Read ERR: return FM_ERR_NOCONNECT");
return FM_ERR_NOCONNECT;
}
HANDLE_SERVER_RC(ptr_to_hdr(buff));
} else {
m_connected = false;
FM_ERROR_LOG("Write ERR: return FM_ERR_NOCONNECT");
return FM_ERR_NOCONNECT;
}
return FM_ERR_OK;
}
EFmErrorT fm_get_fault(AlarmFilter *filter, SFmAlarmDataT *alarm ) {
CFmMutexGuard m(getAPIMutex());
if (!fm_lib_reconnect()) return FM_ERR_NOCONNECT;
fm_check_thread_pending_request();
fm_buff_t buff;
buff.clear();
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmGetFault,
filter,sizeof(*filter));
if (erc!=FM_ERR_OK) return erc;
if (m_client.write_packet(buff)) {
if (!m_client.read_packet(buff)) {
m_connected = false;
return FM_ERR_NOCONNECT;
}
HANDLE_SERVER_RC(ptr_to_hdr(buff));
CHECK_RESPONSE(ptr_to_hdr(buff),SFmAlarmDataT);
SFmAlarmDataT * data = (SFmAlarmDataT * ) ptr_to_data(buff);
*alarm = *data;
} else {
m_connected = false;
return FM_ERR_NOCONNECT;
}
return FM_ERR_OK;
}
EFmErrorT fm_get_faults(fm_ent_inst_t *inst_id,
SFmAlarmDataT *alarm,
unsigned int *max_alarms_to_get) {
CFmMutexGuard m(getAPIMutex());
if (!fm_lib_reconnect()) return FM_ERR_NOCONNECT;
fm_check_thread_pending_request();
fm_buff_t buff;
buff.clear();
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmGetFaults,
(*inst_id),sizeof(*inst_id));
if (erc!=FM_ERR_OK) return erc;
if (m_client.write_packet(buff)) {
if(!m_client.read_packet(buff)) {
m_connected = false;
return FM_ERR_NOCONNECT;
}
if (ptr_to_hdr(buff)->msg_rc != FM_ERR_OK) {
*max_alarms_to_get = 0;
EFmErrorT rc = (EFmErrorT)ptr_to_hdr(buff)->msg_rc;
return rc;
}
uint32_t pkt_size = ptr_to_hdr(buff)->msg_size;
if (pkt_size < sizeof(uint32_t)) {
FM_ERROR_LOG("Received invalid pkt size: %u\n",pkt_size );
m_connected = false;
return FM_ERR_COMMUNICATIONS;
}
pkt_size-=sizeof(uint32_t);
char *dptr = (char*)ptr_to_data(buff);
uint32_t *len = (uint32_t*)dptr;
dptr+=sizeof(uint32_t);
if (*max_alarms_to_get < *len) {
return FM_ERR_NOT_ENOUGH_SPACE;
}
if (pkt_size < (*len*sizeof(SFmAlarmDataT))) {
return FM_ERR_COMMUNICATIONS;
}
*max_alarms_to_get = *len;
memcpy(alarm,dptr,pkt_size);
} else {
m_connected = false;
return FM_ERR_NOCONNECT;
}
return FM_ERR_OK;
}
EFmErrorT fm_get_faults_by_id(fm_alarm_id *alarm_id,
SFmAlarmDataT *alarm,
unsigned int *max_alarms_to_get) {
CFmMutexGuard m(getAPIMutex());
if (!fm_lib_reconnect()) return FM_ERR_NOCONNECT;
fm_check_thread_pending_request();
fm_buff_t buff;
buff.clear();
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmGetFaultsById,
(*alarm_id), sizeof(*alarm_id));
if (erc!=FM_ERR_OK) return erc;
if (m_client.write_packet(buff)) {
if (!m_client.read_packet(buff)) {
m_connected = false;
return FM_ERR_NOCONNECT;
}
if (ptr_to_hdr(buff)->msg_rc != FM_ERR_OK){
*max_alarms_to_get = 0;
EFmErrorT rc = (EFmErrorT)ptr_to_hdr(buff)->msg_rc;
return rc;
}
uint32_t pkt_size = ptr_to_hdr(buff)->msg_size;
if (pkt_size < sizeof(uint32_t)) {
FM_ERROR_LOG("Received invalid pkt size: %u\n",pkt_size );
m_connected = false;
return FM_ERR_COMMUNICATIONS;
}
pkt_size-=sizeof(uint32_t);
char *dptr = (char*)ptr_to_data(buff);
uint32_t *len = (uint32_t*)dptr;
dptr+=sizeof(uint32_t);
if (*max_alarms_to_get < *len) {
return FM_ERR_NOT_ENOUGH_SPACE;
}
if (pkt_size < (*len*sizeof(SFmAlarmDataT)) ) {
return FM_ERR_COMMUNICATIONS;
}
*max_alarms_to_get = *len;
memcpy(alarm,dptr,pkt_size);
} else {
m_connected = false;
return FM_ERR_NOCONNECT;
}
return FM_ERR_OK;
}
/*
* APIs that enqueue the request and return ok for acknowledgment.
* A backgroup thread will pick up the request and send it to the FM Manager
*/
EFmErrorT fm_set_fault_async(const SFmAlarmDataT *alarm, fm_uuid_t *uuid) {
if ( !fm_lib_thread()) return FM_ERR_RESOURCE_UNAVAILABLE;
CHECK_LIST_FULL(GetListOfFmRequests());
fm_uuid_t id;
fm_buff_t buff;
buff.clear();
fm_uuid_create(id);
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmCreateFault,
alarm, sizeof(*alarm));
if (erc != FM_ERR_OK) return erc;
memcpy(ptr_to_data(buff), id, sizeof(fm_uuid_t)-1);
FM_INFO_LOG("Enqueue raise alarm request: UUID (%s) alarm id (%s) instant id (%s)",
id, alarm->alarm_id, alarm->entity_instance_id);
enqueue(buff);
if (uuid != NULL) {
memcpy(*uuid,id,sizeof(*uuid)-1);
}
return FM_ERR_OK;
}
EFmErrorT fm_clear_fault_async(AlarmFilter *filter) {
if ( !fm_lib_thread()) return FM_ERR_RESOURCE_UNAVAILABLE;
CHECK_LIST_FULL(GetListOfFmRequests());
fm_buff_t buff;
buff.clear();
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmDeleteFault,
filter, sizeof(*filter));
if (erc!=FM_ERR_OK) return erc;
FM_INFO_LOG("Enqueue clear alarm request: alarm id (%s), instant id (%s)",
filter->alarm_id, filter->entity_instance_id);
enqueue(buff);
return FM_ERR_OK;
}
EFmErrorT fm_clear_all_async(fm_ent_inst_t *inst_id) {
if ( !fm_lib_thread()) return FM_ERR_RESOURCE_UNAVAILABLE;
CHECK_LIST_FULL(GetListOfFmRequests());
fm_buff_t buff;
buff.clear();
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmDeleteFaults,
(*inst_id), sizeof(*inst_id));
if (erc!=FM_ERR_OK) return erc;
FM_INFO_LOG("Enqueue clear all alarm request: instant id (%s)", *inst_id);
enqueue(buff);
return FM_ERR_OK;
}
}