blob: 356d371c8d30dcd5afdfe647bd39c203faf8face [file] [log] [blame]
/*******************************************************************************
* 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;
}