📄 ipmi_con.cpp
字号:
/* * ipmi_con.c * * Interface code for handling IPMI connections * * Copyright (c) 2003,2004 by FORCE Computers. * * 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. This * file and program are licensed under a BSD style license. See * the Copying file included with the OpenHPI distribution for * full licensing terms. * * Authors: * Thomas Kanngieser <thomas.kanngieser@fci.com> */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <assert.h>#include <errno.h>#include <poll.h>#include "ipmi_con.h"cIpmiCon::cIpmiCon( unsigned int timeout, int log_level ) : m_is_open( false ), m_fd( -1 ), m_slave_addr( 0x20 ), m_max_outstanding( 1 ), m_queue( 0 ), m_num_outstanding( 0 ), m_current_seq( 0 ), m_exit( false ), m_log_level( log_level ), m_timeout( timeout ), m_check_connection( false ){ // m_log_level = dIpmiConLogEvent; for( int i = 0; i < dMaxSeq; i++ ) m_outstanding[i] = 0; m_last_receive_timestamp = cTime::Now();}cIpmiCon::~cIpmiCon(){ assert( !IsRunning() ); RequeueOutstanding(); while( m_queue ) { cIpmiRequest *r = (cIpmiRequest *)m_queue->data; delete r; m_queue = g_list_remove( m_queue, r ); }}voidcIpmiCon::RequeueOutstanding(){ for( int i = 0; i < dMaxSeq; i++ ) { if ( m_outstanding[i] == 0 ) continue; if ( m_outstanding[i]->m_retries_left == 0 ) m_outstanding[i]->m_retries_left = 1; m_queue = g_list_append( m_queue, m_outstanding[i] ); RemOutstanding( i ); }}intcIpmiCon::AddOutstanding( cIpmiRequest *r ){ assert( m_num_outstanding < m_max_outstanding ); // find next free seq while( true ) { if ( m_outstanding[m_current_seq] == 0 ) break; m_current_seq++; m_current_seq %= m_max_seq; } r->m_seq = m_current_seq; assert( m_outstanding[m_current_seq] == 0 ); m_outstanding[m_current_seq] = r; m_num_outstanding++; m_current_seq++; m_current_seq %= m_max_seq; return r->m_seq;}voidcIpmiCon::RemOutstanding( int seq ){ assert( seq >= 0 && seq < dMaxSeq ); if ( m_outstanding[seq] == 0 ) { assert( 0 ); return; } m_outstanding[seq] = 0; m_num_outstanding--; assert( m_num_outstanding >= 0 );}voidcIpmiCon::HandleMsgError( cIpmiRequest *r, SaErrorT err ){ // try again if ( r->m_retries_left > 0 ) { m_log_lock.Lock(); stdlog << "timeout: resending message.\n"; m_log_lock.Unlock(); m_queue = g_list_append( m_queue, r ); // if a check connection is not in progress // initiate a check connection cTime timeout = m_last_receive_timestamp; timeout += m_timeout; if ( !m_check_connection && timeout < cTime::Now() ) { m_check_connection = true; bool check = IfCheckConnection( timeout ); if ( !check ) m_check_connection = false; else m_check_connection_timeout = timeout; } return; } // error while sending command m_log_lock.Lock(); if ( err == SA_ERR_HPI_TIMEOUT ) stdlog << ">tim " << (unsigned char)r->m_seq << "\n"; else stdlog << ">err " << (unsigned char)r->m_seq << " " << err << "\n"; m_log_lock.Unlock(); r->m_error = err; r->m_signal->Lock(); r->m_signal->Signal(); r->m_signal->Unlock();}SaErrorTcIpmiCon::SendCmd( cIpmiRequest *request ){ assert( m_num_outstanding < m_max_outstanding ); request->m_retries_left--; assert( request->m_retries_left >= 0 ); int seq = AddOutstanding( request ); if ( m_log_level & dIpmiConLogCmd ) { m_log_lock.Lock(); stdlog << ">cmd " << (unsigned char)seq << " "; IpmiLogDataMsg( request->m_addr, request->m_msg ); stdlog << "\n"; m_log_lock.Unlock(); } // message timeout request->m_timeout = cTime::Now(); // add timeout request->m_timeout += m_timeout; // addr translation IfAddrToSendAddr( request->m_addr, request->m_send_addr ); // send message SaErrorT rv = IfSendCmd( request ); if ( rv != SA_OK ) { RemOutstanding( seq ); return rv; } return SA_OK;}voidcIpmiCon::SendCmds(){ while( m_queue && m_num_outstanding < m_max_outstanding ) { cIpmiRequest *r = (cIpmiRequest *)m_queue->data; m_queue = g_list_remove( m_queue, r ); SaErrorT rv = SendCmd( r ); if ( rv != SA_OK ) HandleMsgError( r, rv ); }}void *cIpmiCon::Run(){ stdlog << "starting reader thread.\n"; // create pollfd struct pollfd pfd; pfd.events = POLLIN; // reader loop while( !m_exit ) { // check for check connction timeout if ( m_check_connection ) { cTime now = cTime::Now(); if ( now >= m_check_connection_timeout ) { IfCheckConnectionTimeout(); // if a new connection is established // resend messages m_queue_lock.Lock(); SendCmds(); m_queue_lock.Unlock(); m_check_connection = false; } } assert( m_fd >= 0 ); // do this before every poll(), // because m_fd can change pfd.fd = m_fd; int rv = poll( &pfd, 1, 100 ); if ( rv == 1 ) // read response IfReadResponse(); else if ( rv != 0 ) { if ( errno != EINTR ) { // error stdlog << "poll returns " << rv << ", " << errno << ", " << strerror( errno ) << " !\n"; assert( 0 ); abort(); } } // check for expiered ipmi commands cTime now = cTime::Now(); m_queue_lock.Lock(); for( int i = 0; i < m_max_seq; i++ ) { if ( m_outstanding[i] == 0 ) continue; cIpmiRequest *r = m_outstanding[i]; if ( r->m_timeout > now ) continue; stdlog << "IPMI msg timeout: addr " << r->m_addr.m_slave_addr << " " << IpmiCmdToString( r->m_msg.m_netfn, r->m_msg.m_cmd ) << ", seq " << (unsigned char)r->m_seq << ", timeout " << (int)r->m_timeout.m_time.tv_sec << " " << (int)r->m_timeout.m_time.tv_usec << ", now " << (int)now.m_time.tv_sec << " " << (int)now.m_time.tv_usec << "!\n"; // timeout expired RemOutstanding( r->m_seq ); HandleMsgError( r, SA_ERR_HPI_TIMEOUT ); } // send new comands SendCmds(); m_queue_lock.Unlock(); } stdlog << "stop reader thread.\n"; return 0;}voidcIpmiCon::IfClose(){}voidcIpmiCon::IfAddrToSendAddr( const cIpmiAddr &addr, cIpmiAddr &send_addr ){ // address translation send_addr = addr; if ( addr.m_type == eIpmiAddrTypeIpmb || addr.m_type == eIpmiAddrTypeIpmbBroadcast ) { if ( addr.m_slave_addr == m_slave_addr ) { // Most systems don't handle sending to your own slave // address, so we have to translate here. send_addr.Si(); send_addr.m_lun = addr.m_lun; } }}boolcIpmiCon::IfCheckConnection( cTime & /*timeout*/ ){ // no connection check return false;}voidcIpmiCon::IfCheckConnectionTimeout(){}voidcIpmiCon::HandleCheckConnection( bool state ){ if ( state ) m_last_receive_timestamp = cTime::Now(); m_check_connection = false;}boolcIpmiCon::Open(){ if ( IsOpen() ) return true; m_max_seq = IfGetMaxSeq(); assert( m_max_seq > 0 && m_max_seq <= dMaxSeq ); m_fd = IfOpen(); if ( m_fd == -1 ) return false; m_last_receive_timestamp = cTime::Now(); m_exit = false; // start reader thread if ( !Start() ) return false; m_is_open = true; return true;}voidcIpmiCon::Close(){ if ( !IsOpen() ) return; assert( IsRunning() ); // signal reader thread to terminate m_exit = true; // wait for reader thread void *rv; Wait( rv ); IfClose(); m_is_open = false;}// send an ipmi command and wait for response.SaErrorTcIpmiCon::Cmd( const cIpmiAddr &addr, const cIpmiMsg &msg, cIpmiAddr &rsp_addr, cIpmiMsg &rsp, int retries ){ assert( retries > 0 ); SaErrorT rv; assert( msg.m_data_len <= dIpmiMaxMsgLength ); assert( IsRunning() ); int idx = addr.m_slave_addr; // use 0 for system interface if ( addr.m_type == eIpmiAddrTypeSystemInterface ) idx = 0; cThreadCond cond; // create request cIpmiRequest *r = new cIpmiRequest( addr, msg ); r->m_rsp_addr = &rsp_addr; r->m_rsp = &rsp; r->m_signal = &cond; r->m_error = SA_ERR_HPI_INVALID_CMD; r->m_retries_left = retries; // lock queue cond.Lock(); m_queue_lock.Lock(); if ( m_num_outstanding < m_max_outstanding ) { // send the command within this thread context. rv = SendCmd( r ); if ( rv != SA_OK ) { // error delete r; m_queue_lock.Unlock(); cond.Unlock(); return rv; } } else { stdlog << "send queue full.\n"; m_queue = g_list_append( m_queue, r ); } m_queue_lock.Unlock(); // wait for response cond.Wait(); cond.Unlock(); rv = r->m_error; delete r; if ( rv == SA_OK ) { assert( (tIpmiNetfn)(msg.m_netfn | 1) == rsp.m_netfn ); assert( msg.m_cmd == rsp.m_cmd ); } return rv;}SaErrorTcIpmiCon::ExecuteCmd( const cIpmiAddr &addr, const cIpmiMsg &msg, cIpmiMsg &rsp_msg, int retries ){ cIpmiAddr rsp_addr; return Cmd( addr, msg, rsp_addr, rsp_msg, retries );}voidcIpmiCon::HandleResponse( int seq, const cIpmiAddr &addr, const cIpmiMsg &msg ){ m_last_receive_timestamp = cTime::Now(); m_queue_lock.Lock(); if ( m_outstanding[seq] == 0 ) { m_log_lock.Lock(); stdlog << "reading response without request:\n"; stdlog << "# " << (unsigned char)seq << " "; IpmiLogDataMsg( addr, msg ); stdlog << "\n"; m_log_lock.Unlock(); m_queue_lock.Unlock(); return; } cIpmiRequest *r = m_outstanding[seq]; assert( r->m_seq == seq ); if ( m_log_level & dIpmiConLogCmd ) { m_log_lock.Lock(); stdlog << "<rsp " << (unsigned char)r->m_seq << " "; IpmiLogDataMsg( addr, msg ); stdlog << "\n"; m_log_lock.Unlock(); } RemOutstanding( seq ); // addr translation *r->m_rsp_addr = addr; // convert braodcast to ipmb if ( r->m_rsp_addr->m_type == eIpmiAddrTypeIpmbBroadcast ) r->m_rsp_addr->m_type = eIpmiAddrTypeIpmb; r->m_error = SA_OK; *r->m_rsp = msg; r->m_signal->Lock(); r->m_signal->Signal(); r->m_signal->Unlock(); m_queue_lock.Unlock();}voidcIpmiCon::HandleEvent( const cIpmiAddr &addr, const cIpmiMsg &msg ){ m_last_receive_timestamp = cTime::Now(); if ( m_log_level & dIpmiConLogEvent ) { m_log_lock.Lock(); stdlog << ">evt "; IpmiLogDataMsg( addr, msg ); stdlog << "\n"; m_log_lock.Unlock(); } HandleAsyncEvent( addr, msg );}voidIpmiLogDataMsg( const cIpmiAddr &addr, const cIpmiMsg &msg ){ char str[1024]; char *s = str; // addr switch( addr.m_type ) { case eIpmiAddrTypeIpmb: s += sprintf( s, "%02x %02x %02x %02x", eIpmiAddrTypeIpmb, addr.m_channel, addr.m_lun, addr.m_slave_addr ); break; case eIpmiAddrTypeSystemInterface: s += sprintf( s, "%02x %02x %02x", eIpmiAddrTypeSystemInterface, addr.m_channel, addr.m_lun ); break; case eIpmiAddrTypeIpmbBroadcast: s += sprintf( s, "%02x %02x %02x %02x", eIpmiAddrTypeIpmbBroadcast, addr.m_channel, addr.m_lun, addr.m_slave_addr ); } // msg s += sprintf( s, " %02x %02x %02x ", msg.m_netfn, msg.m_cmd, msg.m_data_len ); const unsigned char *p = msg.m_data; for( int i = 0; i < msg.m_data_len; i++ ) s += sprintf( s, " %02x", *p++ ); stdlog << str;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -