Validate fm manager socket fd before send a message

When fm manager is restarted, there is no mechanism to detect it
from fm api client side. As a result, when subcloud delete clear
alarm request is sent after fm manager is restarted, fm api client
will show broke pipe and clear alarm request is not received and
this alarm stays.

This fix is to check socket fd state before send/receive from
fm api client. If broken pipe is detected, it will try to
reconnect to fm manager.

Closes-bug: 2039684

Test Plan:
PASS: Restart fm manager and confirm that detect broken pipe
      and reconnect messages in /var/log. For example,
-----
sm: err fmSocket.cpp(270): A broken pipe error occurred
sm: warning fmAPI.cpp(116): Invalid file descriptor. Atte
mpting to reconnect...
sm: info fmAPI.cpp(149): Connected to FM Manager.
-----
PASS: Delete offline subcloud and confirm the alarm is
      removed.

Change-Id: Ibc0f4d96b5c0a385d8fedbc1acd23898f1cbea46
Signed-off-by: Takamasa Takenaka <takamasa.takenaka@windriver.com>
This commit is contained in:
Takamasa Takenaka 2023-10-12 19:21:44 -03:00
parent 1fb9ffdc54
commit 8bd6e5b92d
3 changed files with 32 additions and 3 deletions

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Wind River Systems, Inc.
// Copyright (c) 2017,2023 Wind River Systems, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@ -106,6 +106,18 @@ static bool dequeue(fm_buff_t &req) {
static bool fm_lib_reconnect() {
char addr[INET6_ADDRSTRLEN];
if (m_connected) {
// Check fd is valid
// When fm manager is restarted, it is possible to
// have broken pipe. This checks fd is valid or not.
// If not, set m_connected false, so that it will
// try to connect in the following while loop.
if (!m_client.fd_valid()) {
FM_WARNING_LOG("Invalid file descriptor. Attempting to reconnect...");
m_connected = false;
}
}
while (!m_connected) {
struct addrinfo hints;
struct addrinfo *result = NULL, *rp;

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Wind River Systems, Inc.
// Copyright (c) 2017,2023 Wind River Systems, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@ -10,6 +10,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <errno.h>
#include <unistd.h>
@ -259,6 +260,21 @@ int CFmSocket::select_read(int fd,int timeout, bool &timedout){
return select(&fd,1,NULL,0,timeout,0,timedout);
}
bool CFmSocket::fd_valid(){
struct pollfd pfd = {.fd = m_fd, .events = POLLRDHUP};
if ((poll(&pfd, 1, 0)) < 0) {
return false;
} else {
if (pfd.revents & POLLRDHUP) {
// broken pipe
FM_ERROR_LOG("A broken pipe error occurred\n");
return false;
} else {
return true;
}
}
}
bool CFmSocket::recvfrom(void *data, long &len, CFmSockAddr &addr) {
socklen_t addr_len = sizeof(addr.address);
int l = ::recvfrom(m_fd,data,len,0,addr.get_sockaddr(),&addr_len);

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2014 Wind River Systems, Inc.
// Copyright (c) 2014,2023 Wind River Systems, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
@ -67,6 +67,7 @@ public:
int get_fd() { return m_fd; }
bool fd_valid();
bool recvfrom(void *data, long &len, CFmSockAddr &addr );
static int select(int *rfd, int rlen, int *wfds, int wlen,int timeout,int timeoutusec, bool &timedout);