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");
	}
}
Exemple #2
0
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);
	}
}
Exemple #5
0
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();
}
Exemple #7
0
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);	
}
Exemple #8
0
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());
	}

}
Exemple #9
0
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;
		}
	}
}
Exemple #13
0
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);
}
Exemple #17
0
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
}
Exemple #20
0
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;
	}
}
Exemple #21
0
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;
}
Exemple #22
0
TaskResult VtoTransmitTask::_OnPartialResponse(const APDU& arAPDU)
{
	LOG_BLOCK(LEV_ERROR,
	          "Non fin responses not allowed for task: "
	          << this->Name());

	return TR_CONTINUE;
}
Exemple #23
0
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();
	}
}
Exemple #25
0
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);
	}
}
Exemple #29
0
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);
	}
}
Exemple #30
0
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);
	}
}