| /******************************************************************************* |
| * 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(){ |
| |
| 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, nullptr, nullptr, &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)) && (nullptr != 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 *mFDSet){ |
| TFileDescriptor nRetVal = scmInvalidFileDescriptor; |
| FD_ZERO(mFDSet); |
| TConnectionContainer::Iterator itEnd(mConnectionsList.end()); |
| for(TConnectionContainer::Iterator itRunner = mConnectionsList.begin(); itRunner != itEnd; ++itRunner){ |
| FD_SET(itRunner->mSockDes, mFDSet); |
| if(itRunner->mSockDes > nRetVal || scmInvalidFileDescriptor == nRetVal){ |
| nRetVal = itRunner->mSockDes; |
| } |
| } |
| mConnectionListChanged = false; |
| return nRetVal; |
| } |