/******************************************************************************* | |
* Copyright (c) 2010 - 2014 ACIN, Profactor GmbH, fortiss GmbH | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License 2.0 which is available at | |
* http://www.eclipse.org/legal/epl-2.0. | |
* | |
* SPDX-License-Identifier: EPL-2.0 | |
* | |
* Contributors: | |
* Alois Zoitl, Gerhard Ebenhofer, Ingo Hegny | |
* - initial API and implementation and/or initial documentation | |
*******************************************************************************/ | |
#include <sockhand.h> //needs to be first pulls in the platform specific includes | |
#include "fdselecthand.h" | |
#include "devlog.h" | |
#include "../core/devexec.h" | |
#include "../core/cominfra/commfb.h" | |
#include "../core/cominfra/comCallback.h" | |
#include "../core/utils/criticalregion.h" | |
DEFINE_HANDLER(CFDSelectHandler) | |
CFDSelectHandler::CFDSelectHandler(CDeviceExecution& paDeviceExecution) : CExternalEventHandler(paDeviceExecution) { | |
mConnectionListChanged = false; | |
#ifdef WIN32 | |
// Windows Socket Startupcode | |
WORD wVersionRequested; | |
WSADATA wsaData; | |
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ | |
wVersionRequested = MAKEWORD(2, 2); | |
WSAStartup(wVersionRequested, &wsaData); | |
#endif | |
} | |
CFDSelectHandler::~CFDSelectHandler(){ | |
this->end(); | |
#ifdef WIN32 | |
WSACleanup(); | |
#endif | |
} | |
// single-threaded-network-code | |
void CFDSelectHandler::run(void){ | |
struct timeval tv; | |
fd_set anFDSet; | |
fd_set anFDSetMaster; | |
TFileDescriptor nHighestFDID = scmInvalidFileDescriptor; | |
int retval = 0; | |
FD_ZERO(&anFDSetMaster); | |
while(isAlive()){ | |
// TODO: create method to prevent 100ms timeout on reconnection | |
mSync.lock(); | |
if(true == mConnectionListChanged){ | |
nHighestFDID = createFDSet(&anFDSetMaster); | |
} | |
anFDSet = anFDSetMaster; | |
mSync.unlock(); | |
tv.tv_sec = 1; //TODO : To be set! | |
tv.tv_usec = 0; | |
if(scmInvalidFileDescriptor != nHighestFDID){ | |
retval = select(static_cast<int>(nHighestFDID + 1), &anFDSet, NULL, NULL, &tv); | |
if(!isAlive()){ | |
//the thread has been closed in the meantime do not process any messages anymore | |
return; | |
} | |
} | |
else{ | |
retval = 0; | |
} | |
if(retval > 0){ | |
mSync.lock(); | |
TConnectionContainer::Iterator itEnd(mConnectionsList.end()); | |
for(TConnectionContainer::Iterator itRunner = mConnectionsList.begin(); itRunner != itEnd;){ | |
// need to retrieve the callee as the iterator may get invalid in the recvDat function below in case of connection closing | |
forte::com_infra::CComCallback *callee = itRunner->mCallee; | |
TFileDescriptor sockDes = itRunner->mSockDes; | |
++itRunner; | |
if((0 != FD_ISSET(sockDes, &anFDSet)) && (0 != callee)){ | |
mSync.unlock(); | |
if(forte::com_infra::e_Nothing != callee->recvData(&sockDes,0)){ | |
startNewEventChain(callee->getCommFB()); | |
} | |
mSync.lock(); | |
} | |
} | |
mSync.unlock(); | |
} | |
else{ | |
if(retval != 0) { | |
#ifdef WIN32 | |
DEVLOG_ERROR("Select failed: %d", WSAGetLastError()); | |
#else | |
DEVLOG_ERROR("Select failed: %s", strerror(errno)); | |
#endif | |
} | |
} | |
} | |
} | |
void CFDSelectHandler::addComCallback(TFileDescriptor paFD, forte::com_infra::CComCallback *paComCallback){ | |
{ | |
CCriticalRegion criticalRegion(mSync); | |
TConnContType stNewNode = { paFD, paComCallback }; | |
mConnectionsList.pushBack(stNewNode); | |
mConnectionListChanged = true; | |
} | |
if(!isAlive()){ | |
this->start(); | |
} | |
} | |
void CFDSelectHandler::removeComCallback(TFileDescriptor paFD){ | |
CCriticalRegion criticalRegion(mSync); | |
TConnectionContainer::Iterator itRunner(mConnectionsList.begin()); | |
TConnectionContainer::Iterator itRefNode(mConnectionsList.end()); | |
TConnectionContainer::Iterator itEnd(mConnectionsList.end()); | |
while(itRunner != itEnd){ | |
if(itRunner->mSockDes == paFD){ | |
if(itRefNode ==itEnd){ | |
mConnectionsList.popFront(); | |
} | |
else{ | |
mConnectionsList.eraseAfter(itRefNode); | |
} | |
break; | |
} | |
itRefNode = itRunner; | |
++itRunner; | |
} | |
mConnectionListChanged = true; | |
} | |
CFDSelectHandler::TFileDescriptor CFDSelectHandler::createFDSet(fd_set *m_panFDSet){ | |
TFileDescriptor nRetVal = scmInvalidFileDescriptor; | |
FD_ZERO(m_panFDSet); | |
TConnectionContainer::Iterator itEnd(mConnectionsList.end()); | |
for(TConnectionContainer::Iterator itRunner = mConnectionsList.begin(); itRunner != itEnd; ++itRunner){ | |
FD_SET(itRunner->mSockDes, m_panFDSet); | |
if(itRunner->mSockDes > nRetVal || scmInvalidFileDescriptor == nRetVal){ | |
nRetVal = itRunner->mSockDes; | |
} | |
} | |
mConnectionListChanged = false; | |
return nRetVal; | |
} |