From 6e9b6347c4b618870d542d67019ef98f5dc83ed4 Mon Sep 17 00:00:00 2001 From: LX3JL Date: Fri, 1 Jan 2016 05:21:58 +0100 Subject: [PATCH] version 1.1.1 corrected file handle resource leak in CCallsignList::GetLastModTime() --- src/ccallsignlist.cpp | 89 +++++++++++++++++---------- src/ccallsignlist.h | 9 +-- src/creflector.cpp | 136 ++++++++++++++++++++++-------------------- src/main.h | 4 +- 4 files changed, 134 insertions(+), 104 deletions(-) diff --git a/src/ccallsignlist.cpp b/src/ccallsignlist.cpp index eafa18a..2554054 100644 --- a/src/ccallsignlist.cpp +++ b/src/ccallsignlist.cpp @@ -56,30 +56,36 @@ CCallsignList::~CCallsignList() bool CCallsignList::LoadFromFile(const char *filename) { bool ok = false; - char sz[CALLSIGN_LEN+1]; - + char sz[32]; + // and load std::ifstream file (filename); if ( file.is_open() ) { Lock(); - + // empty list clear(); // fill with file content while ( file.getline(sz, sizeof(sz)).good() ) { - push_back(CCallsign(sz)); + // remove leading & trailing spaces + char *szt = TrimWhiteSpaces(sz); + // and load + if ( ::strlen(szt) > 0 ) + { + push_back(CCallsign(szt)); + } } // close file file.close(); - + // keep file path m_Filename = filename; - + // update time GetLastModTime(&m_LastModTime); - + // and done Unlock(); ok = true; @@ -96,7 +102,7 @@ bool CCallsignList::LoadFromFile(const char *filename) bool CCallsignList::ReloadFromFile(void) { bool ok = false; - + if ( m_Filename != NULL ) { ok = LoadFromFile(m_Filename); @@ -107,7 +113,7 @@ bool CCallsignList::ReloadFromFile(void) bool CCallsignList::NeedReload(void) { bool needReload = false; - + time_t time; if ( GetLastModTime(&time) ) { @@ -116,38 +122,57 @@ bool CCallsignList::NeedReload(void) return needReload; } -bool CCallsignList::GetLastModTime(time_t *time) -{ - bool ok = false; - - if ( m_Filename != NULL ) - { - int file=0; - if( (file = ::open(m_Filename, O_RDONLY)) != -1 ) - { - struct stat fileStat; - if( ::fstat(file, &fileStat) != -1 ) - { - *time = fileStat.st_mtime; - ok = true; - } - } - - } - return ok; -} - //////////////////////////////////////////////////////////////////////////////////////// // compare bool CCallsignList::IsListed(const CCallsign &callsign) const { bool listed = false; - + for ( int i = 0; (i < size()) && !listed; i++ ) { listed = (data()[i]).HasSameCallsignWithWidlcard(callsign); } - + return listed; } + +//////////////////////////////////////////////////////////////////////////////////////// +// helpers + +char *CCallsignList::TrimWhiteSpaces(char *str) +{ + char *end; + + // Trim leading space + while(*str == ' ') str++; + + // All spaces? + if(*str == 0) + return str; + + // Trim trailing space + end = str + ::strlen(str) - 1; + while((end > str) && (*end == ' ')) end--; + + // Write new null terminator + *(end+1) = 0; + + return str; +} + +bool CCallsignList::GetLastModTime(time_t *time) +{ + bool ok = false; + + if ( m_Filename != NULL ) + { + struct stat fileStat; + if( ::stat(m_Filename, &fileStat) != -1 ) + { + *time = fileStat.st_mtime; + ok = true; + } + } + return ok; +} diff --git a/src/ccallsignlist.h b/src/ccallsignlist.h index 5f9496e..3f749f4 100644 --- a/src/ccallsignlist.h +++ b/src/ccallsignlist.h @@ -37,7 +37,7 @@ class CCallsignList : public std::vector public: // constructor CCallsignList(); - + // destructor virtual ~CCallsignList(); @@ -49,14 +49,15 @@ public: bool LoadFromFile(const char *); bool ReloadFromFile(void); bool NeedReload(void); - + // compare bool IsListed(const CCallsign &) const; - + protected: // bool GetLastModTime(time_t *); - + char *TrimWhiteSpaces(char *); + protected: // data std::mutex m_Mutex; diff --git a/src/creflector.cpp b/src/creflector.cpp index 7ae773f..dfcc8fb 100644 --- a/src/creflector.cpp +++ b/src/creflector.cpp @@ -19,7 +19,7 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with Foobar. If not, see . +// along with Foobar. If not, see . // ---------------------------------------------------------------------------- #include "main.h" @@ -87,28 +87,28 @@ CReflector::~CReflector() bool CReflector::Start(void) { bool ok = true; - + // reset stop flag m_bStopThreads = false; - + // init gate keeper ok &= g_GateKeeper.Init(); - + // create protocols ok &= m_Protocols.Init(); - + // start one thread per reflector module for ( int i = 0; i < NB_OF_MODULES; i++ ) { m_RouterThreads[i] = new std::thread(CReflector::RouterThread, this, &(m_Streams[i])); } - + // start the reporting threads m_XmlReportThread = new std::thread(CReflector::XmlReportThread, this); #ifdef JSON_MONITOR m_JsonReportThread = new std::thread(CReflector::JsonReportThread, this); #endif - + // done return ok; } @@ -117,7 +117,7 @@ void CReflector::Stop(void) { // stop & delete all threads m_bStopThreads = true; - + // stop & delete report threads if ( m_XmlReportThread != NULL ) { @@ -131,7 +131,7 @@ void CReflector::Stop(void) delete m_JsonReportThread; m_JsonReportThread = NULL; } - + // stop & delete all router thread for ( int i = 0; i < NB_OF_MODULES; i++ ) { @@ -142,10 +142,10 @@ void CReflector::Stop(void) m_RouterThreads[i] = NULL; } } - + // close protocols m_Protocols.Close(); - + // close gatekeeper g_GateKeeper.Close(); } @@ -161,10 +161,10 @@ bool CReflector::IsStreaming(char module) CPacketStream *CReflector::OpenStream(CDvHeaderPacket *DvHeader, CClient *client) { CPacketStream *retStream = NULL; - + // clients MUST have bee locked by the caller // so we can freely access it within the fuction - + // check if client is valid candidate if ( m_Clients.IsClient(client) && !client->IsAMaster() ) { @@ -181,14 +181,14 @@ CPacketStream *CReflector::OpenStream(CDvHeaderPacket *DvHeader, CClient *client // stream open, mark client as master // so that it can't be deleted client->SetMasterOfModule(module); - + // update last heard time client->Heard(); retStream = stream; - + // and push header packet stream->Push(DvHeader); - + // report std::cout << "Opening stream on module " << module << " for client " << client->GetCallsign() << " with sid " << DvHeader->GetStreamId() << std::endl; @@ -225,33 +225,33 @@ void CReflector::CloseStream(CPacketStream *stream) CTimePoint::TaskSleepFor(10); } } while (!bEmpty); - + // lock it stream->Lock(); - + // lock clients GetClients(); - + // get and check the master CClient *client = stream->GetOwnerClient(); if ( client != NULL ) { // client no longer a master client->NotAMaster(); - + // notify g_Reflector.OnStreamClose(stream->GetUserCallsign()); - + std::cout << "Closing stream of module " << GetStreamModule(stream) << std::endl; } - + // stop the queue stream->Close(); - - + + // release clients ReleaseClients(); - + // and unlock stream->Unlock(); } @@ -264,10 +264,10 @@ void CReflector::RouterThread(CReflector *This, CPacketStream *streamIn) { // get our module uint8 uiModuleId = This->GetStreamModule(streamIn); - + // get on input queue CPacket *packet; - + while ( !This->m_bStopThreads ) { // any packet in our input queue ? @@ -283,31 +283,31 @@ void CReflector::RouterThread(CReflector *This, CPacketStream *streamIn) packet = NULL; } streamIn->Unlock(); - + // route it if ( packet != NULL ) { // set origin packet->SetModuleId(uiModuleId); - + // iterate on all protocols for ( int i = 0; i < This->m_Protocols.Size(); i++ ) { // duplicate packet CPacket *packetClone = packet->Duplicate(); - + // get protocol CProtocol *protocol = This->m_Protocols.GetProtocol(i); - + // if packet is header, update RPT2 according to protocol if ( packetClone->IsDvHeader() ) - { + { // get our callsign CCallsign csRPT = protocol->GetReflectorCallsign(); csRPT.SetModule(This->GetStreamModule(streamIn)); ((CDvHeaderPacket *)packetClone)->SetRpt2Callsign(csRPT); } - + // and push it CPacketQueue *queue = protocol->GetQueue(); queue->push(packetClone); @@ -317,7 +317,7 @@ void CReflector::RouterThread(CReflector *This, CPacketStream *streamIn) delete packet; packet = NULL; } - + // wait a bit CTimePoint::TaskSleepFor(10); } @@ -341,7 +341,11 @@ void CReflector::XmlReportThread(CReflector *This) // and close file xmlFile.close(); } - + else + { + std::cout << "Failed to open " << XML_PATH << std::endl; + } + // and wait a bit CTimePoint::TaskSleepFor(XML_UPDATE_PERIOD * 1000); } @@ -353,10 +357,10 @@ void CReflector::JsonReportThread(CReflector *This) CBuffer Buffer; CIp Ip; bool bOn; - + // init variable bOn = false; - + // create listening socket if ( Socket.Open(JSON_PORT) ) { @@ -370,26 +374,26 @@ void CReflector::JsonReportThread(CReflector *This) if ( Buffer.Compare((uint8 *)"hello", 5) == 0 ) { std::cout << "Monitor socket connected with " << Ip << std::endl; - + // connected bOn = true; - + // announce ourselves This->SendJsonReflectorObject(Socket, Ip); - + // dump tables - This->SendJsonNodesObject(Socket, Ip); + This->SendJsonNodesObject(Socket, Ip); This->SendJsonStationsObject(Socket, Ip); } else if ( Buffer.Compare((uint8 *)"bye", 3) == 0 ) { std::cout << "Monitor socket disconnected" << std::endl; - + // diconnected bOn = false; } } - + // any notifications ? CNotification notification; This->m_Notifications.Lock(); @@ -444,7 +448,7 @@ void CReflector::JsonReportThread(CReflector *This) void CReflector::OnClientsChanged(void) { CNotification notification(NOTIFICATION_CLIENTS); - + m_Notifications.Lock(); m_Notifications.push(notification); m_Notifications.Unlock(); @@ -453,7 +457,7 @@ void CReflector::OnClientsChanged(void) void CReflector::OnUsersChanged(void) { CNotification notification(NOTIFICATION_USERS); - + m_Notifications.Lock(); m_Notifications.push(notification); m_Notifications.Unlock(); @@ -462,7 +466,7 @@ void CReflector::OnUsersChanged(void) void CReflector::OnStreamOpen(const CCallsign &callsign) { CNotification notification(NOTIFICATION_STREAM_OPEN, callsign); - + m_Notifications.Lock(); m_Notifications.push(notification); m_Notifications.Unlock(); @@ -471,7 +475,7 @@ void CReflector::OnStreamOpen(const CCallsign &callsign) void CReflector::OnStreamClose(const CCallsign &callsign) { CNotification notification(NOTIFICATION_STREAM_CLOSE, callsign); - + m_Notifications.Lock(); m_Notifications.push(notification); m_Notifications.Unlock(); @@ -521,12 +525,12 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile) { // write header xmlFile << "" << std::endl; - + // software version char sz[64]; ::sprintf(sz, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION); xmlFile << "" << sz << "" << std::endl; - + // linked nodes xmlFile << "<" << m_Callsign << "linked nodes>" << std::endl; // lock @@ -539,7 +543,7 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile) // unlock ReleaseClients(); xmlFile << "" << std::endl; - + // last heard users xmlFile << "<" << m_Callsign << "heard users>" << std::endl; // lock @@ -562,7 +566,7 @@ void CReflector::SendJsonReflectorObject(CUdpSocket &Socket, CIp &Ip) char Buffer[1024]; char cs[CALLSIGN_LEN+1]; char mod[8] = "\"A\""; - + // get reflector callsign m_Callsign.GetCallsign((uint8 *)cs); cs[CALLSIGN_LEN] = 0; @@ -579,7 +583,7 @@ void CReflector::SendJsonReflectorObject(CUdpSocket &Socket, CIp &Ip) } } ::strcat(Buffer, "]}"); - + // and send Socket.Send(Buffer, Ip); } @@ -591,7 +595,7 @@ void CReflector::SendJsonNodesObject(CUdpSocket &Socket, CIp &Ip) char Buffer[12+(JSON_NBMAX_NODES*94)]; // nodes object table - ::sprintf(Buffer, "{\"nodes\":["); + ::sprintf(Buffer, "{\"nodes\":["); // lock CClients *clients = GetClients(); // iterate on clients @@ -604,21 +608,21 @@ void CReflector::SendJsonNodesObject(CUdpSocket &Socket, CIp &Ip) } } // unlock - ReleaseClients(); + ReleaseClients(); ::strcat(Buffer, "]}"); - + // and send //std::cout << Buffer << std::endl; Socket.Send(Buffer, Ip); } - + void CReflector::SendJsonStationsObject(CUdpSocket &Socket, CIp &Ip) { char Buffer[15+(LASTHEARD_USERS_MAX_SIZE*94)]; - + // stations object table - ::sprintf(Buffer, "{\"stations\":["); - + ::sprintf(Buffer, "{\"stations\":["); + // lock CUsers *users = GetUsers(); // iterate on users @@ -629,12 +633,12 @@ void CReflector::SendJsonStationsObject(CUdpSocket &Socket, CIp &Ip) { ::strcat(Buffer, ","); } - } + } // unlock ReleaseUsers(); - + ::strcat(Buffer, "]}"); - + // and send //std::cout << Buffer << std::endl; Socket.Send(Buffer, Ip); @@ -644,11 +648,11 @@ void CReflector::SendJsonOnairObject(CUdpSocket &Socket, CIp &Ip, const CCallsig { char Buffer[128]; char sz[CALLSIGN_LEN+1]; - + // onair object Callsign.GetCallsignString(sz); ::sprintf(Buffer, "{\"onair\":\"%s\"}", sz); - + // and send //std::cout << Buffer << std::endl; Socket.Send(Buffer, Ip); @@ -658,11 +662,11 @@ void CReflector::SendJsonOffairObject(CUdpSocket &Socket, CIp &Ip, const CCallsi { char Buffer[128]; char sz[CALLSIGN_LEN+1]; - + // offair object Callsign.GetCallsignString(sz); ::sprintf(Buffer, "{\"offair\":\"%s\"}", sz); - + // and send //std::cout << Buffer << std::endl; Socket.Send(Buffer, Ip); diff --git a/src/main.h b/src/main.h index 0c2bf79..df6ab94 100644 --- a/src/main.h +++ b/src/main.h @@ -19,7 +19,7 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with Foobar. If not, see . +// along with Foobar. If not, see . // ---------------------------------------------------------------------------- #ifndef main_h @@ -48,7 +48,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 1 -#define VERSION_REVISION 0 +#define VERSION_REVISION 1 // global ------------------------------------------------------