bool EnhancedVtoRouter::CheckIncomingVtoData(const VtoData& arData) { switch(arData.GetType()) { case(VTODT_DATA): if(mInstRemoteConnected) return true; else { LOG_BLOCK(LEV_WARNING, "Discarding received data, because remote side is offline"); this->HandleReceivingDataWhenRemoteClosed(); return false; } case(VTODT_REMOTE_OPENED): if(mInstRemoteConnected) { LOG_BLOCK(LEV_WARNING, "Remote side opened, but it was already open"); this->HandleDuplicateOpen(); return false; } else { mInstRemoteConnected = true; return true; } case(VTODT_REMOTE_CLOSED): if(mInstRemoteConnected) { mInstRemoteConnected = false; return true; } else { LOG_BLOCK(LEV_WARNING, "Remote side closed, but it was already closed"); this->HandleDuplicateClose(); return false; } default: throw ArgumentException(LOCATION, "Unknown VtoData type"); } }
void MockAppLayer::SendUnsolicited(APDU& arAPDU) { LOG_BLOCK(LEV_COMM, "=> " << toHex(arAPDU.GetBuffer(), arAPDU.Size(), true)); LOG_BLOCK(LEV_INTERPRET, "=> " << arAPDU.ToString()); mFragments.push_back(arAPDU); this->DoSendUnsol(); }
void AddressScanner::Run() { mRouter.Start(); LOG_BLOCK(LEV_INFO, "Scanning from " << mCurrent << " to " << mStop); mThread.Run(); LOG_BLOCK(LEV_INFO, "Scan complete..."); }
void PhysicalLayerAsyncTCPClient::DoOpenSuccess() { LOG_BLOCK(LEV_INFO, "Connected to: " << mRemoteEndpoint); if (mUseKeepAlives) { LOG_BLOCK(LEV_DEBUG, "Enabling keepalives on the socket connection to " << mRemoteEndpoint); boost::asio::socket_base::keep_alive option(true); mSocket.set_option(option); } }
void AsyncPort::Associate(const std::string& arStackName, AsyncStack* apStack, uint_16_t aLocalAddress) { LOG_BLOCK(LEV_DEBUG, "Linking stack to port: " << aLocalAddress); mStackMap[arStackName] = StackRecord(apStack, aLocalAddress); apStack->mLink.SetRouter(&mRouter); mRouter.AddContext(&apStack->mLink, aLocalAddress); if(!mRouter.IsRunning()) { LOG_BLOCK(LEV_DEBUG, "Starting router"); mRouter.Start(); } }
void Slave::OnUnsolFailure() { // disable unsol responses until request is received from master if (mUnsolExpectCON) { LOG_BLOCK(LEV_WARNING, "Disable unsol response"); mUnsolDisable = true; } mpState->OnUnsolFailure(this); LOG_BLOCK(LEV_WARNING, "Unsol response failure"); this->FlushDeferredEvents(); }
void AsyncPort::Disassociate(const std::string& arStackName) { StackMap::iterator i = mStackMap.find(arStackName); StackRecord r = i->second; LOG_BLOCK(LEV_DEBUG, "Unlinking stack from port: " << r.mLocalAddress); mRouter.RemoveContext(r.mLocalAddress); // decouple the stack from the router and tell the stack to go offline if the it was previously online delete r.pStack; // delete the stack if(mRouter.IsRunning() && mRouter.NumContext() == 0) { LOG_BLOCK(LEV_DEBUG, "Stopping router"); mRouter.Stop(); } mStackMap.erase(i); }
void IOServiceThread::Run() { size_t num = 0; try { num = mpService->run(); } catch(IOServiceExitException&) { LOG_BLOCK(LEV_INFO, "IOService exited via IOServiceExitException"); } catch(const std::exception& ex) { LOG_BLOCK(LEV_ERROR, "Unexpected exception: " << ex.what()); } }
size_t VtoWriter::Write(const boost::uint8_t* apData, size_t aLength, boost::uint8_t aChannelId) { size_t num = 0; { CriticalSection cs(&mLock); /* * Only write the maximum amount available or requested. If the * requested data size is larger than the available buffer space, * only send what will fit. */ num = Min<size_t>(this->NumBytesAvailable(), aLength); /* * Chop up the data into Max(255) segments and add it to the queue. */ this->Commit(apData, num, aChannelId); LOG_BLOCK(LEV_INTERPRET, "VtoWriter: " << this->NumBytesAvailable() << " available out of " << (mMaxVtoChunks * VtoData::MAX_SIZE)); } /* Tell any listeners that the queue has new data to be read. */ if (num > 0) this->NotifyAll(); /* Return the number of bytes from apData that were queued. */ return num; }
void Slave::HandleEnableUnsolicited(const APDU& arRequest, bool aIsEnable) { mResponse.Set(FC_RESPONSE); if (mConfig.mDisableUnsol) { mRspIIN.SetFuncNotSupported(true); } else { if (aIsEnable) { this->mDeferredUnsol = true; } for (HeaderReadIterator hdr = arRequest.BeginRead(); !hdr.IsEnd(); ++hdr) { switch (MACRO_DNP_RADIX(hdr->GetGroup(), hdr->GetVariation())) { case (MACRO_DNP_RADIX(60, 2)): mConfig.mUnsolMask.class1 = aIsEnable; break; case (MACRO_DNP_RADIX(60, 3)): mConfig.mUnsolMask.class2 = aIsEnable; break; case (MACRO_DNP_RADIX(60, 4)): mConfig.mUnsolMask.class3 = aIsEnable; break; default: mRspIIN.SetFuncNotSupported(true); LOG_BLOCK(LEV_WARNING, "Cannot enable/disable unsol for " << hdr->GetBaseObject()->Name()); break; } } } }
void Slave::HandleWriteTimeDate(HeaderReadIterator& arHWI) { if (!mIIN.GetNeedTime()) { LOG_BLOCK(LEV_WARNING, "Master is attempting to write time but slave is not requesting time sync"); return; } ObjectReadIterator obj = arHWI.BeginRead(); if (obj.Count() != 1) { mRspIIN.SetParameterError(true); return; } millis_t val = Group50Var1::Inst()->mTime.Get(*obj); mpTime->SetTime(val); mIIN.SetNeedTime(false); if(mpLogger->IsEnabled(LEV_EVENT)) { LogEntry le(LEV_EVENT, mpLogger->GetName(), LOCATION, "Time synchronized with master", TIME_SYNC_UPDATED); le.AddValue("MILLISEC_SINCE_EPOCH", val); mpLogger->Log(le); } }
void Slave::HandleWriteIIN(HeaderReadIterator& arHdr) { for (ObjectReadIterator obj = arHdr.BeginRead(); !obj.IsEnd(); ++obj) { switch (obj->Index()) { case IINI_DEVICE_RESTART: { bool value = Group80Var1::Inst()->Read(*obj, obj->Start(), obj->Index()); if (!value) { mIIN.SetDeviceRestart(false); } else { mRspIIN.SetParameterError(true); ERROR_BLOCK(LEV_WARNING, "", SERR_INVALID_IIN_WRITE); } break; } case IINI_NEED_TIME: mpTimeTimer->Cancel(); mpTimeTimer = NULL; mIIN.SetNeedTime(false); LOG_BLOCK(LEV_INFO, "Master forced clear time needed flag"); break; default: mRspIIN.SetParameterError(true); ERROR_BLOCK(LEV_WARNING, "", SERR_INVALID_IIN_WRITE); break; } } }
void AppLayerChannel::ChangeState(ACS_Base* apState) { if(apState != mpState) { LOG_BLOCK(LEV_DEBUG, "State changed from " << mpState->Name() << " to " << apState->Name()); mpState = apState; } }
void PhysicalLayerMonitor::_OnLowerLayerUp() { LOG_BLOCK(LEV_DEBUG, "_OnLowerLayerUp"); this->mCurrentRetry = mMinOpenRetry; mpState->OnLayerOpen(this); this->OnPhysicalLayerOpenSuccessCallback(); }
void PhysicalLayerMonitor::_OnOpenFailure() { LOG_BLOCK(LEV_DEBUG, "_OnOpenFailure()"); mpState->OnOpenFailure(this); this->OnPhysicalLayerOpenFailureCallback(); this->mCurrentRetry = std::min(2 * mCurrentRetry, mMaxOpenRetry); }
void PhysicalLayerMonitor::OnOpenTimerExpiration() { LOG_BLOCK(LEV_DEBUG, "OnOpenTimerExpiration()"); assert(mpOpenTimer != NULL); mpOpenTimer = NULL; mpState->OnOpenTimeout(this); }
void VtoRouter::CheckForVtoWrite() { if(!mVtoTxBuffer.empty()) { VtoMessage msg = mVtoTxBuffer.front(); mVtoTxBuffer.pop_front(); // type DATA means this is a buffer and we need to pull the data out and send it to the vto writer if(msg.type == VTODT_DATA) { size_t numWritten = mpVtoWriter->Write(msg.data.Buffer(), msg.data.Size(), this->GetChannelId()); LOG_BLOCK(LEV_INTERPRET, "VtoWriter: " << numWritten << " of " << msg.data.Size()); if(numWritten < msg.data.Size()) { size_t remainder = msg.data.Size() - numWritten; VtoMessage partial(VTODT_DATA, msg.data.Buffer() + numWritten, remainder); mVtoTxBuffer.push_front(partial); } else this->CheckForVtoWrite(); } else { // if we have generated REMOTE_OPENED or REMOTE_CLOSED message we need to send the SetLocalVtoState // update to the vtowriter so it can be serialized in the correct order. mpVtoWriter->SetLocalVtoState(msg.type == VTODT_REMOTE_OPENED, this->GetChannelId()); this->CheckForVtoWrite(); } } this->CheckForPhysRead(); }
void PhysicalLayerAsyncBase::OnOpenCallback(const boost::system::error_code& arErr) { if(mState.mOpening) { mState.mOpening = false; this->DoOpenCallback(); if(arErr) { LOG_BLOCK(LEV_WARNING, arErr.message()); mState.CheckForClose(); this->DoOpenFailure(); if(mpHandler) mpHandler->OnOpenFailure(); } else { // successful connection if(this->IsClosing()) { // but the connection was closed mState.CheckForClose(); this->DoClose(); if(mpHandler) mpHandler->OnOpenFailure(); } else { mState.mOpen = true; this->DoOpenSuccess(); if(mpHandler) mpHandler->OnLowerLayerUp(); } } } else { MACRO_THROW_EXCEPTION_COMPLEX(InvalidStateException, "OnOpenCallback: " << this->ConvertStateToString()); } }
void IUpperLayer::OnReceive(const apl::byte_t* apData, size_t aNumBytes) { if(this->LogReceive()) { LOG_BLOCK(LEV_COMM, RecvString() << " " << toHex(apData, aNumBytes, true)); } this->_OnReceive(apData, aNumBytes); //call the implementation }
void VtoTransmitTask::ConfigureRequest(APDU& arAPDU) { /* * Masters never request confirmed data. The response from the * slave is all that's required for reliable delivery. */ arAPDU.Set(mUseNonStandardCode ? FC_PROPRIETARY_VTO_TRANSFER : FC_WRITE); const size_t MAX_VTO_EVENTS = 7; /* Get all of the data objects in the buffer. */ size_t numObjects = this->mBuffer.Select(PC_ALL_EVENTS, MAX_VTO_EVENTS); LOG_BLOCK(LEV_INTERPRET, "VtoTransmitTask Sending: " << numObjects << " of " << this->mBuffer.Size()); /* If there are no objects to write, skip the remainder. */ if (numObjects == 0) { return; } /* * Loop through the selected data and add corresponding objects to * the arAPDU instance. */ VtoDataEventIter vto = this->mBuffer.Begin(); for (size_t i = 0; i < numObjects; ++i) { /* Insert a new object into the APDU message. */ IndexedWriteIterator itr = arAPDU.WriteIndexed( Group112Var0::Inst(), vto->mValue.GetSize(), vto->mIndex ); /* * Check to see if the APDU fragment has enough room for the * data segment. If the fragment is full, return out of this * function and let the fragment send. */ if (itr.IsEnd()) { return; } /* Set the object index */ itr.SetIndex(vto->mIndex); /* Write the data to the APDU message */ Group112Var0::Inst()->Write( *itr, vto->mValue.GetSize(), vto->mValue.mpData ); /* Mark the data segment as being written */ vto->mWritten = true; /* Move to the next data segment in the buffer */ ++vto; } }
bool LinkLayerReceiver::ValidateHeader() { //first thing to do is check the CRC if(!DNPCrc::IsCorrectCRC(mBuffer.ReadBuff(), LI_CRC)) { mCrcFailures.Increment(); ERROR_BLOCK(LEV_ERROR, "CRC failure in header", DLERR_CRC); return false; } if(!mHeader.ValidLength()) { ERROR_BLOCK(LEV_ERROR, "LENGTH out of range [5,255]: " << static_cast<int>(mHeader.GetLength()), DLERR_INVALID_LENGTH); return false; } LOG_BLOCK(LEV_INTERPRET, "<~ " << mHeader.ToString()); // some combinations of these header parameters are invalid // check for them here //Now make sure that the function code is known and that the FCV is appropriate if(!this->ValidateFunctionCode()) return false; boost::uint8_t user_data_length = mHeader.GetLength() - LS_MIN_LENGTH; mFrameSize = LinkFrame::CalcFrameSize(user_data_length); FuncCodes func = mHeader.GetFuncEnum(); // make sure that the presence/absence of user data // matches the function code if(func == FC_PRI_CONFIRMED_USER_DATA || func == FC_PRI_UNCONFIRMED_USER_DATA) { if(user_data_length > 0) { //mFrameSize = LinkFrame::CalcFrameSize(user_data_length); } else { ERROR_BLOCK(LEV_ERROR, "User data packet received with zero payload. FUNCTION: " << func, DLERR_NO_DATA); return false; } } else { if(user_data_length > 0) { ERROR_BLOCK(LEV_ERROR, "Unexpected LENGTH in frame: " << static_cast<int>(user_data_length) << " with FUNCTION: " << func, DLERR_UNEXPECTED_DATA); return false; } } if(user_data_length > 0) { if(func == FC_PRI_CONFIRMED_USER_DATA || func == FC_PRI_UNCONFIRMED_USER_DATA) { } else { ERROR_BLOCK(LEV_ERROR, "Unexpected LENGTH in frame: " << static_cast<int>(user_data_length) << " with FUNCTION: " << func, DLERR_UNEXPECTED_DATA); return false; } } else { if(func == FC_PRI_CONFIRMED_USER_DATA || func == FC_PRI_UNCONFIRMED_USER_DATA) { ERROR_BLOCK(LEV_ERROR, "User data packet received with zero payload. FUNCTION: " << func, DLERR_NO_DATA); return false; } } return true; }
TaskResult VtoTransmitTask::_OnPartialResponse(const APDU& arAPDU) { LOG_BLOCK(LEV_ERROR, "Non fin responses not allowed for task: " << this->Name()); return TR_CONTINUE; }
TaskResult SimpleRspBase::_OnFinalResponse(const APDU& arAPDU) { if(arAPDU.BeginRead().Count() > 0) { LOG_BLOCK(LEV_WARNING, "Unexpected object headers in response: " << this->Name()); } return TR_SUCCESS; }
void EnhancedVtoRouter::DoVtoRemoteConnectedChanged(bool aOpened) { if(mRemoteConnected != aOpened) { LOG_BLOCK(LEV_INFO, "Remote connection: " << GetConnectionString(aOpened)); mRemoteConnected = aOpened; this->HandleVtoRemoteConnectedChanged(); } }
void Database::_Update(const Binary& arPoint, size_t aIndex) { if(UpdateValue<Binary>(mBinaryVec, arPoint, aIndex)) { LOG_BLOCK(LEV_DEBUG, "Binary Change: " << arPoint.ToString() << " Index: " << aIndex); BinaryInfo& v = mBinaryVec[aIndex]; if(mpEventBuffer) mpEventBuffer->Update(v.mValue, v.mClass, aIndex); } }
void AsyncSlaveTestObject::SendToSlave(const std::string& arData, SequenceInfo aSeq) { HexSequence hs(arData); mAPDU.Reset(); mAPDU.Write(hs, hs.Size()); mAPDU.Interpret(); LOG_BLOCK(LEV_INTERPRET, "<= " << mAPDU.ToString()); slave.OnRequest(mAPDU, aSeq); }
size_t Slave::FlushUpdates() { size_t num = 0; try { num = mChangeBuffer.FlushUpdates(mpDatabase); } catch (Exception& ex) { LOG_BLOCK(LEV_ERROR, "Error in flush updates: " << ex.Message()); Transaction tr(mChangeBuffer); mChangeBuffer.Clear(); return 0; } num += this->FlushVtoUpdates(); LOG_BLOCK(LEV_DEBUG, "Processed " << num << " updates"); return num; }
void EnhancedVtoRouter::SetLocalConnected(bool aConnected) { if(mLocalConnected != aConnected) { LOG_BLOCK(LEV_INFO, "Local connection: " << GetConnectionString(aConnected)); mLocalConnected = aConnected; this->HandleSetLocalConnected(); this->NotifyRemoteSideOfState(aConnected); } }
void Database::_Update(const Counter& arPoint, size_t aIndex) { if(UpdateValue<Counter>(mCounterVec, arPoint, aIndex)) { LOG_BLOCK(LEV_DEBUG, "Counter Change: " << arPoint.ToString() << " Index: " << aIndex); mCounterVec[aIndex].mLastEventValue = mCounterVec[aIndex].mValue.GetValue(); CounterInfo& v = mCounterVec[aIndex]; if(mpEventBuffer) mpEventBuffer->Update(v.mValue, v.mClass, aIndex); } }
void Database::_Update(const Analog& arPoint, size_t aIndex) { if(UpdateValue<Analog>(mAnalogVec, arPoint, aIndex)) { LOG_BLOCK(LEV_DEBUG, "Analog Change: " << arPoint.ToString() << " Index: " << aIndex); mAnalogVec[aIndex].mLastEventValue = mAnalogVec[aIndex].mValue.GetValue(); AnalogInfo& v = mAnalogVec[aIndex]; if(mpEventBuffer) mpEventBuffer->Update(v.mValue, v.mClass, aIndex); } }