| /******************************************************************************* | |
| * Copyright (c) 2010 - 2014 ACIN, Profactor GmbH, fortiss GmbH | |
| * All rights reserved. This program and the accompanying materials | |
| * are made available under the terms of the Eclipse Public License v1.0 | |
| * which accompanies this distribution, and is available at | |
| * http://www.eclipse.org/legal/epl-v10.html | |
| * | |
| * 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){ | |
| // printf("."); | |
| } | |
| else{ | |
| #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; | |
| } |